<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Matjaž Domen Pečan</title>
    <description>The latest articles on Forem by Matjaž Domen Pečan (@mpecan).</description>
    <link>https://forem.com/mpecan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3814224%2F12e7e17a-d791-498e-a8a8-59a74c603269.jpg</url>
      <title>Forem: Matjaž Domen Pečan</title>
      <link>https://forem.com/mpecan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mpecan"/>
    <language>en</language>
    <item>
      <title>Going deeper: Intercepting subcommands in Make, Just, and Git Hooks</title>
      <dc:creator>Matjaž Domen Pečan</dc:creator>
      <pubDate>Mon, 09 Mar 2026 08:08:07 +0000</pubDate>
      <link>https://forem.com/mpecan/going-deeper-intercepting-subcommands-in-make-just-and-git-hooks-44kk</link>
      <guid>https://forem.com/mpecan/going-deeper-intercepting-subcommands-in-make-just-and-git-hooks-44kk</guid>
      <description>&lt;p&gt;If you haven't seen it yet, I have been working on tokf, a command and hook combo that helps me reduce the amount of tokens injected into Claude Code when commands like &lt;code&gt;cargo test&lt;/code&gt; are run. The initial post about it can be found &lt;a href="https://dev.to/posts/tokf-a-different-approach-to-token-compression"&gt;here&lt;/a&gt;. The main benefit of doing this is increasing the amount of context available to Claude Code, which generally leads to better results.&lt;/p&gt;

&lt;h1&gt;
  
  
  Going deeper
&lt;/h1&gt;

&lt;p&gt;I started by using the hooks to intercept the commands being run and modify them to be run by tokf instead, this works well when Claude Code simply tries to run a command like &lt;code&gt;cargo test&lt;/code&gt;. A lot of the time, however, that simple command will be part of a Justfile or a Makefile. This means that being able to intercept &lt;code&gt;just test&lt;/code&gt; doesn't let us filter the subcommands. We need to go deeper, we need to be able to intercept the commands that &lt;code&gt;just&lt;/code&gt; tries to run, not only &lt;code&gt;just&lt;/code&gt; itself.&lt;/p&gt;

&lt;h1&gt;
  
  
  Shell interception
&lt;/h1&gt;

&lt;p&gt;Both &lt;code&gt;make&lt;/code&gt; and &lt;code&gt;just&lt;/code&gt; allow us to set up a shell which they can use to execute the commands that have been configured. This means we have a way to insert ourselves between the tool and the execution.&lt;/p&gt;

&lt;p&gt;With a justfile as the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Run all checks
check: fmt-check lint test file-size

# Format code
fmt:
    cargo fmt

# Check formatting
fmt-check:
    cargo fmt -- --check

# Run unit tests (no database required)
test:
    cargo test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A call to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will end up calling &lt;code&gt;cargo test&lt;/code&gt; internally. We already have a system for rewriting commands, so we do exactly that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="c"&gt;#   becomes&lt;/span&gt;
just &lt;span class="nt"&gt;--shell&lt;/span&gt; tokf &lt;span class="nt"&gt;--shell-arg&lt;/span&gt; &lt;span class="nt"&gt;-cu&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are able to intercept the commands, but wait - tokf isn't a shell, is it?&lt;/p&gt;

&lt;p&gt;The answer is no, it isn't and it doesn't try to be, it also doesn't need to be. We can just delegate work to the shell, but this does allow us to rewrite commands before having the shell execute them.&lt;/p&gt;

&lt;p&gt;So when &lt;code&gt;just test&lt;/code&gt; tries to invoke &lt;code&gt;cargo test&lt;/code&gt;, we now have the ability to sub in &lt;code&gt;tokf run cargo test&lt;/code&gt;, which will allow &lt;code&gt;tokf&lt;/code&gt; to filter the content of the internal command.&lt;/p&gt;

&lt;p&gt;There is a risk doing this, as we have implemented a workaround for a bug in Claude Code - if &lt;code&gt;exit code != 0&lt;/code&gt; then Claude Code duplicates any command output and doubles the context usage for no reason. Our solution was to make tokf always return a 0 exit code, but print out the actual exit code as text. &lt;/p&gt;

&lt;p&gt;Commands that we run in processes like &lt;code&gt;make&lt;/code&gt; then need to return the actual exit code, &lt;code&gt;make&lt;/code&gt; relies on it. So we added the flag &lt;code&gt;--no-mask-exit-code&lt;/code&gt;, which prevents the exit code from being changed.&lt;/p&gt;

&lt;p&gt;Now we have a working interception that works for both &lt;code&gt;make&lt;/code&gt; and &lt;code&gt;just&lt;/code&gt; and would work with most of the tools that do a similar thing (like &lt;code&gt;mise&lt;/code&gt;), just a rewrite away.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting hooked on hooks
&lt;/h1&gt;

&lt;p&gt;Git hooks are a different beast, compared to &lt;code&gt;make&lt;/code&gt; and &lt;code&gt;just&lt;/code&gt;, we cannot just inject a shell to make it execute our wanted commands with. But it executes binaries at some point. How does the shell know where an executable is, anyway?&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;PATH&lt;/code&gt; variable. It defines the lookup for an executable in a hierarchical manner (&lt;code&gt;PATH&lt;/code&gt; is delimited with &lt;code&gt;:&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We can check the value by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;span class="c"&gt;#/usr/bin:/bin:/usr/sbin:/sbin:/opt/podman/bin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells the shell to look for executables in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;/usr/bin&lt;/li&gt;
&lt;li&gt;/bin&lt;/li&gt;
&lt;li&gt;/usr/sbin&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And so forth. This means that if we put our own path in front of the rest, we can define what the binaries actually are, essentially we use simple shims to redirect calls to tokf instead.&lt;/p&gt;

&lt;p&gt;An example shim would be the following one for &lt;code&gt;go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s1"&gt;'tokf'&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'go'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ends up just delegating the command to tokf as a shell (which is what we created before). Now we also have the ability to intercept &lt;code&gt;git-hooks&lt;/code&gt; or any other command that runs subcommands by looking them up in the path.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We are now able to intercept commands in tooling that orchestrates work, no more massive content being created because of a hook failing, instead we now get clear and concise information, filtered to include the minimum required context.&lt;/p&gt;

&lt;p&gt;I also learned a lot about how commands like &lt;code&gt;make&lt;/code&gt; and &lt;code&gt;just&lt;/code&gt; work under the hood during this work, I found solutions which I didn't think of before, like shimming the commands and intercepting them + delegating them to &lt;code&gt;tokf&lt;/code&gt; instead. &lt;/p&gt;

&lt;p&gt;If you are also looking to extend your Claude Code sessions and reduce the number of compactions, then try out &lt;code&gt;tokf&lt;/code&gt;, all instructions available at &lt;a href="https://tokf.net" rel="noopener noreferrer"&gt;tokf.net&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>cli</category>
      <category>ai</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
