Measured 2026-08-29 · rtk 0.46.0 · macOS

RTK: what the numbers actually say

Two people replied to the thread saying RTK costs them tokens rather than saving them. The savings are real and large. So is the failure they describe. Everything below was measured on this machine today, not reasoned about.

↓ הסבר מלא בעברית: מה בדיוק הם טוענים

64.6Mtokens saved, lifetime
31.2%average reduction
47,075commands proxied
25match ceiling on grep output
13%of Bash calls are rewritable at all

01 · the headline

The savings are real, and they are not evenly spread

rtk gain reports 64.6M tokens saved across 47,075 proxied commands, a 31.2% average reduction on 206.9M input tokens. That number is true. It is also an average over wildly different commands, and the average is the least useful way to read it.

tokens saved per command family

Top 10 by tokens saved. Percentages are RTK's own average reduction for that command.

One row carries the whole story: 568 test runs saved 28.6M tokens, which is 44% of everything RTK has ever saved here. A test runner's summary genuinely is the useful output, so compressing the other 15% of its log costs nothing.

02 · concentration

1.3% of commands produce 46% of the savings

Split the 64.6M by what kind of command earned it. Test and lint runners (vitest, pytest, eslint) are 623 commands, 1.3% of the total, and they account for 29.6M. Search and read (grep, read, find) are 9,448 commands, 20% of the total, for 23.3M.

test + lint runners search + read process snapshots gh pr diff everything else

Segments sum to 64.5M against a reported 64.6M total. The gap is rounding in RTK's own display.

Familycommandsshare of cmdssavedshare of savings
test + lint runners6231.3%29.6M46%
search + read9,44820.1%23.3M36%
process snapshots290.1%2.4M4%
gh pr diff1750.4%1.3M2%
everything else36,80078.2%7.9M12%

This matters because the two halves carry different risk. The runner half has no retry risk: nobody needs line 400 of a passing vitest log. The search half is where the complaint lives.

03 · the complaint

The failure they describe is real, and it has an exact shape

@TheOnlyKatz, 2026-08-29 01:10

RTK תמיד היה רק מבזבז לי טוקנים ולא חוסך, לא חסרות פקודות שהסוכן מנסה לבצע שעם RTK לא מחזירות באמת את המידע ההכרחי ואז הוא צריך לעשות עוד 10 איטרציות עם RTK כדי לקבל את המידע.

RTK only ever wasted tokens for me. Plenty of commands do not return the information the agent needs, so it takes another 10 iterations to get it.

@RonSher160268, 2026-08-29 05:18

גם משתמש ב rtk. היו כמה פעמים שהסוכן היה צריך לעקוף את זה כי ה output לא הכיל משהו. מתחיל לחשוב שהחיסכון פה זה אשליה ואולי זה גורם לסוכנים לעבוד יותר

Also an RTK user. Several times the agent had to bypass it because the output was missing something. Starting to think the saving is an illusion and it may make agents work more.

I ran 20 (pattern, file) pairs through plain grep and rtk grep on real repository files, from inside a script file, which the hook cannot rewrite, so grep was genuinely plain. The divergence is deterministic: rtk grep prints at most 25 matches. Thirteen pairs matched exactly, every one of them at or under 25. Seven diverged, every one of them over 25. Zero divergences below the ceiling.

true match count 25 match ceiling

The seven pairs that diverged. In all seven, RTK printed exactly 25 matches.

Table view: all 20 pairs
PatternFiletrueshownVerdict

04 · deep dive · עברית

מה בדיוק הם טוענים, שורה אחר שורה

קודם כול, מה RTK בכלל עושה

RTK הוא לא ספרייה ולא MCP. הוא הוק מסוג PreToolUse שיושב על כלי ה־Bash של Claude Code. לפני שכל פקודת שורת פקודה רצה, ההוק מיירט את מחרוזת הפקודה, שואל את הבינארי של RTK אם יש לה מקבילה מקוצרת, ואם יש, מחליף אותה.

הסוכן ביקש grep -n hook README.md. מה שרץ בפועל הוא rtk grep -n hook README.md. הפלט שחוזר לתוך ההקשר של הסוכן הוא הפלט המקוצר, וזו בדיוק הנקודה: הסוכן קיבל תשובה אחרת מזו שהוא ביקש, והוא לא בהכרח מודע לכך.

הטענה של Amit, מפורקת לשלושה חלקים

  1. "לא מחזירות באמת את המידע ההכרחי". זו טענה על שלמות הפלט, לא על פורמט. הוא לא אומר שהפלט מכוער, הוא אומר שחסר בו תוכן.
  2. "עוד 10 איטרציות". זו טענה על עלות. כל ניסיון חוזר הוא תור נוסף, כלומר עוד פרומפט מלא, עוד פלט, ועוד זמן.
  3. "מבזבז לי טוקנים ולא חוסך". זו המסקנה: סך העלות של הלולאה גדול מהחיסכון של הקיצור הבודד.

מדדתי את המנגנון שעומד מאחורי הטענה הראשונה, והוא קיים ומדויק: rtk grep מדפיס לכל היותר 25 התאמות, לא משנה כמה יש באמת. בקובץ src/hooks/README.md יש 219 שורות שמכילות את המילה hook. RTK מדפיס 25 מהן.

למה תקרה של 25 מייצרת לולאה

ההבדל הקריטי הוא בין קריאה לבין חיפוש. כשקוראים קובץ, 25 השורות הראשונות הן התחלה סבירה. כשמחפשים, ההתאמה שמעניינת אותך יכולה להיות מספר 40, ואין שום סיבה שהיא תהיה בין 25 הראשונות.

1
הסוכן מחפש הוא מריץ חיפוש רחב כדי למצוא איפה מוגדר משהו. בעיניו זו פקודה אחת שמחזירה את כל ההתאמות.
2
הוא מקבל 25 מתוך 219 אף אחת מהן היא לא מה שהוא חיפש. מבחינת התוכן שחזר, זו תשובה שלילית.
3
הוא לא יודע להבדיל בין שתי אפשרויות או שמה שחיפש נמצא ב־194 שנחתכו, או שהוא פשוט לא קיים בקובץ. שתי האפשרויות נראות זהות.
4
אז הוא מצמצם ומריץ שוב ביטוי חיפוש צר יותר, קובץ ספציפי יותר, דגל אחר. כל צמצום כזה הוא תור נוסף.
5
וזו הלולאה שהוא מתאר לא באג, לא קריסה. פשוט חיפוש שמחזיר תשובה חלקית שנראית כמו תשובה מלאה.

יש כאן גם סיכון חמור יותר מבזבוז זמן, וזה מה ש־Ron מתאר כ־"the output לא הכיל משהו": היעדר שקרי. אם הסוכן מסיק "המחרוזת הזו לא קיימת" כשהיא כן קיימת בשורה 100, הוא לא סתם מבזבז תור. הוא בונה על מסקנה שגויה. זה בדיוק מה שקרה לי ב־24 באוגוסט, ובגלל זה כתבתי אז פתק זיכרון על הנושא.

מה RTK כן אומר לך, וזה החלק שאף אחד בשרשור לא הזכיר

RTK לא משקר ולא מסתיר. הוא מודיע על הקיצוץ פעמיים, בהתחלה ובסוף:

219 matches in 1 files:

3:TypeScript hook system for the OrchestKit Claude Plugin...
...
66:│   │   ├── mcp/            # MCP integration hooks
  +194 more in src/hooks/README.md [see remaining: tail -n +26 "$HOME/.../1787985624_grep_0_s_da1929.log"]

השורה הראשונה אומרת שיש 219 התאמות. השורה האחרונה אומרת ש־194 נחתכו, ונותנת את הפקודה המדויקת לשלוף אותן. כלומר המידע לשבור את הלולאה נמצא שם, בתוך הפלט.

אבל שים לב שזה עובד רק אם שני תנאים מתקיימים: הסוכן צריך לקרוא את הכותרת ואת הכותרת התחתונה, והוא צריך לבחור להריץ את ה־tail במקום פשוט לנסח מחדש את החיפוש. שתי ההתנהגויות האלה אינן מובטחות. וגם כשהוא כן מריץ את ה־tail, זו עדיין קריאה שנייה, כלומר תור נוסף. כלומר החוויה שהם מתארים נשארת נכונה, היא פשוט פחות דרמטית ממה שהם חושבים.

כמה זה קורה בפועל? כל קיצוץ כותב קובץ יומן. תיקיית היומנים מחזיקה בערך עשרה ימים, ויש בה 7 קיצוצים של grep, אחד מהם נוצר על ידי הבדיקה הזו עצמה. כלומר שישה אירועים אמיתיים בעשרה ימים של עבודה כבדה. זה שיעור נמוך.

הטענה של Ron: "החיסכון הוא אשליה"

זו הטענה החכמה בשרשור, והיא נכונה ברמה מבנית. RTK מודד כמה בייטים הוא הוריד מפקודה אחת. אין לו שום שדה בשביל הקריאה השנייה שהוא עצמו גרם לה. אם הסוכן מריץ אחר כך את ה־tail שהוצע לו, RTK רושם אותה כפקודה נפרדת בחיסכון של בערך אפס אחוז.

מה שהמדד רואה                 מה שקרה באמת
─────────────────────         ──────────────────────────────
rtk grep   -97.9%  WIN        rtk grep    2,004 tok   קוצץ
                              rtk tail      ~900 tok   שליפה
                              ─────────────────────────
נרשם: ניצחון אחד              בפועל: שתי קריאות, שני תורות

לכן "החיסכון הוא אשליה" הוא ניסוח חזק מדי, כי 46 אחוז מהחיסכון מגיע מ־623 הרצות של בדיקות, ושם אין שום סיכון ללולאה. אבל "המדד הזה לא יכול להוכיח שהוא לא אשליה" הוא ניסוח מדויק לחלוטין, וזה מה שנכון להודות בו.

למה "אז לא הגדרת טוב" לא מחזיק

זו הטענה היחידה בשרשור שלא שורדת מדידה, וכדאי לתקן אותה. Amit ענה שהכלי הוא plug & play ושההגדרה היחידה הרלוונטית היא config.exclude_commands. הוא צודק, ובדקתי גם למה:

  • הכפתור הרלוונטי מתועד אבל לא עובד. ל־rtk grep יש דגל -m, --max עם ברירת מחדל 200. הרצתי אותו עם 200, עם 500 ועם 1000. בכל שלוש הפעמים חזרו בדיוק 25 התאמות ובדיוק 2,003 בייטים. הדגל אינרטי.
  • לכן ההחרגה היא בינארית. אי אפשר לומר "תשאיר לי grep אבל בלי התקרה". אפשר רק להחריג את grep לגמרי, וזה מוותר על 16.8 מיליון טוקנים של חיסכון אמיתי.
  • וההחרגה היא לפי פקודה, אחת אחת. כלומר בכל פעם שפקודה חדשה מכניסה את הסוכן ללולאה, צריך לגלות אותה ולהוסיף אותה ידנית. זה בדיוק מה ש־Amit אמר שלא שווה את הזמן, והוא צודק.

ולמה יכול להיות שגם הם צודקים וגם אני, באותו זמן

הרצתי rtk gain --all וקיבלתי פירוק ל־88 ימים. וזה משנה את כל הוויכוח. אחוז החיסכון היומי נע בין 0.2 אחוז ל־99.7 אחוז. אין יום טיפוסי. הממוצע של 31.2 אחוז לא מתאר אף יום אמיתי, והוא בדיוק המספר שעליו מתווכחים בשרשור.

  • שלושה ימים (29 ביולי, 26 ביולי, 15 ביולי) נשאו 106.2 מיליון טוקנים, שהם 51 אחוז מכל מה ש־RTK ראה אי פעם, וייצרו 2.7 מיליון חיסכון, שהם 4 אחוזים.
  • שלושה ימים אחרים (6 באוגוסט, 11 ביוני, 24 ביולי) נשאו 31.3 מיליון וייצרו 30.4 מיליון חיסכון, שהם 47 אחוז מכל החיסכון, בקצב של 97 אחוז.

כלומר זה לא כלי עם הנחה קבועה של 31 אחוז. זה כלי שבחלק מסוגי העבודה הוא כמעט כסף חינם, ובחלק אחר הוא תקורה נטו. הממוצע מסתיר איזה מהשניים אתה חווה כרגע.

ולכן ייתכן מאוד ש־Amit ו־Ron פשוט חיים במצב השני. אם העבודה שלהם לא מייצרת פלטים ענקיים, RTK מסנן פלט שלא היה נפוח מלכתחילה, החיסכון זניח, ועלות הקיצוץ לא מתקזזת. ה־31.2 אחוז שלי הוא לא ראיה נגד החוויה שלהם, כי ה־31.2 אחוז שלי הוא בעצמו תערובת של ימים של 99.7 אחוז וימים של 0.2 אחוז.

והמספר שסוגר את הוויכוח: 65 מיליון טוקנים הם חצי אחוז מהחשבון

ל־RTK יש פקודה שלישית שאף אחד בשרשור לא הריץ, rtk cc-economics. היא מצליבה את החיסכון שלו מול ההוצאה בפועל, וזו התצוגה היחידה שמתרגמת טוקנים לכסף.

  • הוצאה כוללת: $78,041.36
  • חיסכון של RTK: $402.56, כלומר 0.5 אחוז
  • הסיבה נמצאת באותו פלט: קריאות מטמון הן 75.2 מיליארד טוקנים, מול 194.5 מיליון טוקני קלט טריים בלבד.

RTK רואה רק פלט של פקודות שנכנס להקשר. הוא לא נוגע ולא יכול לגעת בקריאות מטמון, ושם נמצא כמעט כל התשלום. לכן החיסכון אמיתי, אבל הוא חצי אחוז מהחשבון, ושום כוונון של תקרת ה־grep לא ישנה את היחס הזה.

שים לב גם שלשלושת המספרים הראשיים של RTK יש פער של שתי סדרי גודל ביניהם: 31.2 אחוז (ממוצע שמערבב ימים של 0.2 עם ימים של 99.7), 54.2 אחוז "מהמכסה החודשית" (שמשווה חיסכון של כתשעים יום מול מכסה של חודש אחד, כלומר מנופח פי שלושה בציר הזמן), ו־0.5 אחוז מהכסף. האחרון הוא היחיד שאני מוכן להגן עליו.

אז מה כן אפשר להגדיר

בדקתי שלושה כפתורים מתועדים שאמורים להרים את התקרה, וכולם מתים: -m/--max בשורת הפקודה, grep_max_per_file בקובץ ההגדרות (בדקתי גם 5, שהיה אמור להקטין, ולא קרה כלום), ו־--ultra-compact. מה שכן עובד זה exclude_commands, והוא מדויק: אחרי שהוספתי grep -q, הוא הפסיק לעבור דרך RTK בזמן ש־grep -n המשיך לחסוך את 16.8 המיליון שלו.

והתגלית שלא ציפיתי לה: 87 אחוז מהפקודות שלי בכלל לא ניתנות לשכתוב

בהתחלה טענתי שההוק של RTK לא עובד על המכונה הזו. טעיתי, ובדקתי את זה כמו שצריך: Claude Code רושם כל הרצת הוק כקובץ מצורף על הקריאה עצמה, עם הפלט של ההוק. על פני שבעה ימים ו־16,493 פקודות Bash, ההוק שכתב 96.6 אחוז מהפקודות שהוא מסוגל לשכתב. הוא עובד.

הבעיה האמיתית אחרת לגמרי: רק 13 אחוז מהפקודות הן בצורה ש־RTK יודע לשכתב. 46 אחוז הן קבצי סקריפט שנכתבים דרך heredoc, ו־RTK לא רואה מה יש בתוך heredoc. זה לא מקרה. יש לי כלל גלובלי שאומר "פקודות ארוכות או מרובות שלבים, תכתוב לקובץ ותריץ אותו", והוק שמזכיר את זה בכל פרומפט, מסיבה טובה: גלישת שורות בטרמינל מפרידה דגל מהארגומנט שלו. הכלל עושה את עבודתו. והוא גם, בשקט, הסיבה הכי גדולה ש־RTK נוגע ב־13 אחוז מהפקודות במקום ב־50.

שני מנגנוני הגנה שלי נלחמו זה בזה, ואף אחד מהם לא יכול היה לראות את השני. זו לא תקלה לתקן, זו הכרעה לקבל עם המספרים מול העיניים.

הפסיקה, טענה אחר טענה

הטענההפסיקההראיה
RTK חוסך הרבה טוקניםמחזיק 64.6 מיליון על פני 47,075 פקודות
RTK מחזיר פלט חסרמחזיק תקרה של 25 התאמות, שוחזרה ב־7 מתוך 20
וזה עולה באיטרציות נוספותחלקית מוצהר בכותרת ובתחתית, ושישה אירועים בעשרה ימים
החיסכון הוא אשליהחצי נכון לגבי צורת המדידה, לא נכון לגבי חצי ההרצות
"אז לא הגדרת טוב"לא נתמך התקרה היא ברירת מחדל, והדגל שהיה אמור לשנות אותה לא עובד

כל המספרים כאן נמדדו על המכונה הזו ב־29 באוגוסט 2026, מול rtk 0.46.0. אפשר לשחזר כל אחד מהם בפקודה אחת.

05 · the part the thread missed

RTK does not hide the truncation. It announces it twice.

The capped output opens with the true total and closes with the shortfall plus the exact recovery command:

$ rtk grep -n "hook" src/hooks/README.md
219 matches in 1 files:

3:TypeScript hook system for the OrchestKit Claude Plugin...
...
66:│   │   ├── mcp/            # MCP integration hooks
  +194 more in src/hooks/README.md [see remaining: tail -n +26 "$HOME/.../1787985624_grep_0_s_da1929.log"]

That call went from 93,281 bytes to 2,004 bytes, a 97.9% reduction, while stating up front that 219 matches exist and 194 are one tail away. So this is not a silent lie. It is a disclosed trade with a documented escape hatch, and it only breaks when the agent skips the header or prefers to reformulate over running the tail.

Two corrections to my own prior notes while I am here. First, the case recorded on 2026-08-24, where grep supposedly could not find a string at line 991 of cc-triage.mjs, does not reproduce on 0.46.0: all six matches come back. Second, I earlier called the ceiling 26. It is 25. I had been counting RTK's own N matches in 1 files: header line as a match.

06 · the knob that does not turn

The documented fix for the ceiling is inert

There are two documented ways to raise the ceiling and a third documented way to compress harder. All three are inert. If any of them worked, the ceiling would be a configuration question and "you configured it wrong" would have a leg to stand on.

1. The CLI flag. rtk grep --help advertises -m, --max <MAX> Max results to show [default: 200].

Invocationmatchesbytes
rtk grep -n hook README.md252,003
... -m 200252,003
... -m 500252,003
... -m 1000252,003

2. The config key. RTK's own config --create template, and the upstream docs, both ship a [limits] block whose grep_max_per_file = 25 is exactly the ceiling I measured. Tested against the real config file, with a backup, in both directions:

grep_max_per_filematches printed
absent (baseline)25
30025
6025
525

The 5 row is the decisive one: a value below the ceiling should have shrunk the output, and did not. The positive control matters here, because a config that is never read looks identical to a key that is ignored. Setting [tee] enabled = false in the same file visibly changed the output, dropping the [see remaining: tail ...] hint from the footer. So the file is read and this key is ignored.

3. The compression flag. --ultra-compact, documented as a global "Level 2 optimizations" flag:

Commandnormalultradelta
rtk grep -n hook README.md2,003 B2,003 B0.0%
rtk ls -la src/hooks541 B541 B0.0%
rtk git status127 B127 B0.0%
rtk git log -206,314 B6,314 B0.0%

Same class of defect already found in rtk rewrite, whose --help promises exit 0 or 1 and which actually exits 3 with the rewrite on stdout. Documented contract, different behaviour.

What does work is [hooks] exclude_commands, and it is precise. After adding "grep -q", grep -q stopped being rewritten while grep -n kept its 16.8M. The list to add comes from rtk gain --failures, which logs 7,688 parse failures at a 100% recovery rate: grep -q 673 times (a predicate, where the exit code is the answer), uv sync 96, git stash 13, docker ps --format 8. Those are commands paying the RTK detour for nothing.

07 · adjudication

Scoring the thread

ClaimVerdictEvidence
RTK saves a lot of tokensHOLDS 64.6M over 47,075 commands, 31.2% average
RTK returns incomplete outputHOLDS 25 match ceiling, reproduced in 7 of 20 pairs
...and that costs extra iterationsBOUNDED disclosed twice; six real spills in ten days
The saving is an illusionHALF true of the accounting, false of the runner half
"You did not configure it properly"NOT SUPPORTED default behaviour, and -m is documented but inert

08 · the time series

The 31.2% average is the least honest number on this page

rtk gain --all breaks the lifetime figure into 88 days. Daily reduction ranges from 0.2% to 99.7%. There is no typical day. Averaging across that distribution produces a number that describes none of it, and it is the number the thread is arguing about.

tokens removed tokens passed through

Bar width is total input tokens, so it shows volume and rate on one axis. May 2026 is omitted at 82.7K input, too small to draw.

July is the interesting month: the highest volume by far, and the worst rate. Three days explain almost all of it.

Dayinputsavedrate
2026-07-2967.4M2.2M3.2%
2026-07-2620.0M506.9K2.5%
2026-07-1518.8M38.9K0.2%
those three106.2M2.7M2.6%
2026-08-0612.0M11.9M99.7%
2026-06-1112.2M11.7M95.4%
2026-07-247.1M6.8M96.2%
those three31.3M30.4M97.1%

Read those two blocks together. Three days carried 51% of every token RTK has ever seen and produced 4% of the savings. Three other days produced 47% of all savings. This is not a tool with a 31% discount rate. It is a tool that is nearly free money on some workloads and pure overhead on others, and the lifetime average hides which one you are having.

That reframes the whole argument. Amit and Ron are not necessarily wrong about their own machines: they may simply be living in the low-compression mode, where RTK filters output that was never bulky to begin with and the truncation cost is not offset. My 31.2% is not evidence against their experience, because my own 31.2% is itself a blend of 99.7% days and 0.2% days.

09 · the money

65 million tokens is 0.5% of the bill

RTK ships a third view nobody in the thread ran. rtk cc-economics joins its own savings against ccusage's spend figure, and it is the only view that converts tokens into money. It is also the one that settles the argument.

Spent (ccusage):              $78,041.36
  Input:                      194.5M
  Output:                     203.0M
  Cache writes:             3,114.6M
  Cache reads:             75,164.4M      <-- RTK cannot touch any of this

RTK commands:                 47,122
Tokens saved:                 65.1M
Estimated savings:           $402.56  (0.5%)

Cache reads are 75.2 billion tokens against 194.5M of fresh input. RTK only ever sees command output entering context, which is a rounding error next to where the spend actually lives. So the savings are real, they are just 0.5% of the bill, and no amount of tuning the grep ceiling changes that ratio.

Which makes RTK's three headline numbers worth ranking, because they disagree with each other by two orders of magnitude:

SourceClaimTrust
rtk gain31.2% average reduction low averages 0.2% days with 99.7% days
rtk gain -q54.2% of monthly quota preserved lowest compares lifetime savings (about 90 days) against a monthly quota
rtk cc-economics$402.56, 0.5% of spend highest

One caveat kept honest: ccusage prices tokens at API list rates, so $78,041 is list-price-equivalent value rather than cash paid on a subscription. The 0.5% ratio survives that, because both sides of it are priced the same way.

10 · and on this machine

The hook was never dead. I was measuring it wrong.

Two earlier versions of this section claimed the hook was not firing and diagnosed why. Both diagnoses were wrong, and so was the claim. The transcript settles it: Claude Code records every hook run as an attachment on the tool call, with the hook's stdout, and RTK's stdout carries the literal string RTK auto-rewrite. That is a per-call record, not an inference.

Session (today)bash callsrewritablerewrittenmissed
7ea749b7 (platform)23577790
a8f68ce0 (platform)15652511
e916de50 (platform)30721210
2d9d60ae (core)34138390
8a1bf14f (orchestkit)356220
553b7d75 (this one)81880

The two commands I offered as proof of a dead hook were both misread, in different ways:

My "proof"What was true
git log --oneline -5 came back native, counter did not move It was rewritten; the transcript has the attachment. rtk git log --oneline output is byte-identical to native (395 B = 395 B), and the counter buffers.
ls -la src/hooks | head -12 came back verbose It has a pipe. rtk rewrite returns nothing for it. Not rewritable, so not a hook failure.

Across the whole estate, 7 days, 582 top-level transcripts:

bash calls        16,493
rewritable         2,174   (13.2%)
rewritten          2,101   hit rate on rewritable  96.6%

of the 156 rewritable calls without a rewrite:
  148  never executed at all (no PreToolUse attachments: interrupted or cancelled)
    4  a hook errored
    3  hooks ran, rtk produced nothing (multi-line commands, 22 Aug)
   -> on calls that actually ran, about 99.7%

So the honest adoption number is not a hook problem. Only 13% of Bash calls on this machine are shapes RTK can rewrite at all. That is the real finding, and it has a cause.

heredoc script pipe simple chain (&& / ;) script file / inline python
Shapecallssharerewritablerewritten
heredoc (cat > x.sh <<'EOF')7,54745.8%013
pipe6,15037.3%1,3721,351
simple9996.1%400329
chain9655.9%402368
run script file6223.8%024
inline python2101.3%016

Top-level session transcripts only; subagent transcripts are not included. A few "rewritten" counts exceed "rewritable" because the shape classifier and rtk rewrite disagree at the margins.

Nearly half of all commands are heredoc script files, and rtk rewrite cannot see inside a heredoc. That shape is not an accident. This machine carries a global rule that says write long, piped, or multi-stage commands to a script file and run that, and a display-lint hook that nudges the same thing on every prompt, for a real reason: terminal line-wrap splits flags from arguments. The rule is doing its job. It is also, silently, the single largest reason RTK touches 13% of commands instead of 50%. Two of my own safeguards were fighting each other, and neither could see the other.

That is a trade-off to decide with the numbers in view, not a bug to fix. It was invisible before because every instrument I reached for first, the buffered counter, the output shape, rtk discover, was answering a different question than the one I asked.

For the record, the two wrong diagnoses and what refuted each: (1) the bare rtk hook claude registration introduced on 22 Aug (commit 5309ba0) broke it: refuted by daily volume, 261 commands/day before vs 241 after with the peak day (928) under the bare form; (2) platform's 27 project-level PreToolUse groups shadow the global hook: refuted by rtk gain --project, platform has the highest adoption on the machine at 17,540 commands and 59.4%. And the instrument that would have prevented all of it, rtk discover, reports 0.0% adoption by construction: transcripts store the model's original command, never the rewritten one, so it cannot see a hook rewrite even when one happened on every call.

One more, found after the restart. I had repointed the registration at a wrapper script and called it harmless hardening. It was not harmless: the wrapper delegated to rtk rewrite, and rtk rewrite ignores RTK_HOOK_AUDIT entirely. Only rtk hook claude writes the audit log. So after the restart the hook was demonstrably rewriting (ls -la came back in rtk's compact form) while rtk hook-audit still reported "No audit log found". The instrument I had just enabled was disabled by the change I made alongside it, and I only caught it because I checked the log instead of assuming it. The wrapper now execs rtk hook claude, keeps the script-path registration, and writes the log. Verified end to end.