<?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>DEV Community: Shengkai Su</title>
    <description>The latest articles on DEV Community by Shengkai Su (@shengkai_su).</description>
    <link>https://dev.to/shengkai_su</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4145751%2Fa2967f00-ecec-487c-8b7d-ffbebf62c084.jpg</url>
      <title>DEV Community: Shengkai Su</title>
      <link>https://dev.to/shengkai_su</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shengkai_su"/>
    <language>en</language>
    <item>
      <title>Cut 91% of Your Tool Prompts: A Practical Guide for Pi Agent Users and Extension Authors</title>
      <dc:creator>Shengkai Su</dc:creator>
      <pubDate>Sun, 27 Sep 2026 16:36:02 +0000</pubDate>
      <link>https://dev.to/shengkai_su/cut-91-of-your-tool-prompts-a-practical-guide-for-pi-agent-users-and-extension-authors-4jo9</link>
      <guid>https://dev.to/shengkai_su/cut-91-of-your-tool-prompts-a-practical-guide-for-pi-agent-users-and-extension-authors-4jo9</guid>
      <description>&lt;p&gt;I've been coding with &lt;a href="https://pi.dev" rel="noopener noreferrer"&gt;Pi Agent&lt;/a&gt; for a while now. What sold me on it is how clean the context is: the system prompt is short, and you're pretty much in control of everything the model sees. The default prompt is only about 2k tokens. Compare that to 10k+ for Codex and 20k+ for Claude Code, and it's a big difference.&lt;/p&gt;

&lt;p&gt;Then I kept installing extensions, and that advantage slowly disappeared. Don't get me wrong, Pi's extension ecosystem is great. Todos, asking questions, web search, subagents: someone has built pretty much anything you'd want. The problem is that a lot of extensions come with really long tool descriptions, and those descriptions get sent in full with every single request. Before you've even said anything, thousands or even tens of thousands of tokens are already gone. That costs money, and it also eats into the model's attention for nothing. Even a model with a 1M context window only has a "smart zone" of about 200k to 300k. The longer your tool descriptions, the less room the model has left for actual work.&lt;/p&gt;

&lt;p&gt;So I made trimmed-down versions of the extensions I use most. I call them lean versions. At first they were just for me, but I figured other people might find them useful, so I open-sourced them. The idea is simple: all the features and logic come straight from upstream, untouched. I only change what the model sees, meaning the tool descriptions and the parameter schemas.&lt;/p&gt;

&lt;p&gt;Here's what that got me:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvp3qyxcayv2bnv7tdvrh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvp3qyxcayv2bnv7tdvrh.png" alt="Tool prompt tokens across 5 Pi extensions: 15,695 upstream vs 1,420 lean, a 91% cut" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Extension&lt;/th&gt;
&lt;th&gt;Lean&lt;/th&gt;
&lt;th&gt;Upstream&lt;/th&gt;
&lt;th&gt;Saved&lt;/th&gt;
&lt;th&gt;Reduction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pi-web-access-lean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;152&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2,953&lt;/td&gt;
&lt;td&gt;2,801&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;94.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rpiv-ask-user-question-lean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;215&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1,258&lt;/td&gt;
&lt;td&gt;1,043&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;82.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rpiv-todo-lean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;248&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;904&lt;/td&gt;
&lt;td&gt;656&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;72.6%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pi-subagents-lean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;268&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8,540&lt;/td&gt;
&lt;td&gt;8,272&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;96.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pi-hashline-edit-pro-lean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;537&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2,040&lt;/td&gt;
&lt;td&gt;1,503&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;73.7%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,420&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15,695&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;14,275&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;91.0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Below I'll walk through how I did it, using the actual upstream text for comparison.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I felt safe cutting this much
&lt;/h2&gt;

&lt;p&gt;I don't think it's fair to blame extension authors for long prompts. A couple of years ago, models really did need them. Without a "MUST" in there, the model just wouldn't call the tool. If you didn't spell out every step, it would go off and do its own thing.&lt;/p&gt;

&lt;p&gt;Models are different now, and Anthropic has said so pretty bluntly in a few pieces this year.&lt;/p&gt;

&lt;p&gt;One is &lt;a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents" rel="noopener noreferrer"&gt;Effective context engineering for AI agents&lt;/a&gt;. It says models, like people, have an "attention budget," and every token in the context spends a bit of it. So what you're looking for is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the smallest possible set of high-signal tokens that maximize the likelihood of some desired outcome&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, get the job done with the fewest tokens that actually matter. There's also a line near the end that I really like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We're already seeing that smarter models require less prescriptive engineering.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The smarter the model, the less you need to hold its hand through every step.&lt;/p&gt;

&lt;p&gt;The other is Claude's official &lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices" rel="noopener noreferrer"&gt;Prompting best practices&lt;/a&gt;. It notes that Claude Opus 4.5 and 4.6 follow system prompts more closely than earlier models. So all the strong language people used to write to stop models from slacking off now makes them overuse tools instead. Their fix:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The fix is to dial back any aggressive language. Where you might have said "CRITICAL: You MUST use this tool when...", you can use more normal prompting like "Use this tool when...".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On Opus 5 they're even more direct. The model already checks its own work, so the "verify before you finish" instruction you carried over from an old prompt just makes it keep checking forever, burning tokens and time. Their advice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;remove these instructions rather than rewriting them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don't rewrite them. Just delete them.&lt;/p&gt;

&lt;p&gt;So my take is that a lot of extension prompts were written for the previous generation of models. Today, some of that text is outdated, and some of it actually works against how newer models behave. Swapping it for something shorter and clearer doesn't make things worse.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 1: Write shorter tool descriptions
&lt;/h2&gt;

&lt;p&gt;This is easier to show than to explain, so let's look at the real text.&lt;/p&gt;

&lt;h3&gt;
  
  
  todo: 904 → 248
&lt;/h3&gt;

&lt;p&gt;Upstream is juicesharp's &lt;a href="https://github.com/juicesharp/rpiv-mono/tree/main/packages/rpiv-todo" rel="noopener noreferrer"&gt;&lt;code&gt;rpiv-todo&lt;/code&gt;&lt;/a&gt;. What it shows the model comes in three parts: a tool description, 8 usage rules, and a description for each parameter. Read them side by side and there's a lot of repetition.&lt;/p&gt;

&lt;p&gt;Here's the upstream text next to my lean version. The parts in red are the repeats:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fao1cxruwxjd9umg81nfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fao1cxruwxjd9umg81nfl.png" alt="rpiv-todo upstream vs lean: upstream explains the status state machine three times and uses all-caps BEFORE and IMMEDIATELY; lean says it once in 248 tokens" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take the task statuses. They're explained three times: in the tool description, in rule 4, and in the &lt;code&gt;status&lt;/code&gt; parameter description. But &lt;code&gt;status&lt;/code&gt; is already an enum. The four values are right there in the schema, and the model gets it the first time. It doesn't need to read a prose version three more times.&lt;/p&gt;

&lt;p&gt;Same with &lt;code&gt;activeForm&lt;/code&gt;: it gets explained three separate times.&lt;/p&gt;

&lt;p&gt;Some of the rules read like instructions for an intern who's bound to mess up. Mark a task in_progress before you start, in all-caps &lt;code&gt;BEFORE&lt;/code&gt;. Mark it completed as soon as you're done, in all-caps &lt;code&gt;IMMEDIATELY&lt;/code&gt;. That's exactly the kind of tone Anthropic says to dial back.&lt;/p&gt;

&lt;p&gt;Rule 1 says to use todo for &lt;code&gt;3+ steps&lt;/code&gt;, and I don't really agree with that either. How many steps justify a todo list is a personal call. Hardcode it in the tool and users can't change it. And if someone has their own rule in AGENTS.md, the two end up fighting each other.&lt;/p&gt;

&lt;p&gt;Here's everything the model sees in my lean version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Tool description
Task tracker. action is required: create|update|list|get|delete|clear;
create needs subject; update/get/delete need id.

# Rules (just one)
Use for multi-step tasks. update needs changed fields; list accepts
status/includeDeleted; clear removes all; create supports blockedBy;
update supports addBlockedBy/removeBlockedBy; keep one in_progress
and complete tasks promptly.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I did four main things.&lt;/p&gt;

&lt;p&gt;First, I removed all the parameter descriptions but kept the schema structure. Field names, types, and enums are all still there. Names like &lt;code&gt;subject&lt;/code&gt;, &lt;code&gt;owner&lt;/code&gt;, and &lt;code&gt;includeDeleted&lt;/code&gt; tell you what they're for at a glance.&lt;/p&gt;

&lt;p&gt;Second, every point is made once. Statuses, &lt;code&gt;activeForm&lt;/code&gt;, and dependencies all get folded into one sentence about which action needs which parameters.&lt;/p&gt;

&lt;p&gt;Third, if code can handle it, the prompt doesn't nag about it. The model sometimes forgets to pass &lt;code&gt;action&lt;/code&gt;, so the code makes a guess: if there's an &lt;code&gt;id&lt;/code&gt; plus fields to change, it's an update; if there's a &lt;code&gt;subject&lt;/code&gt;, it's a create. Rather than telling the model over and over to always pass &lt;code&gt;action&lt;/code&gt;, I just fill it in when it forgets.&lt;/p&gt;

&lt;p&gt;Fourth, decisions like "how many steps before you use this" go back to the user. I changed "3+ steps" to "multi-step tasks," and you set the actual threshold in your own AGENTS.md. Mine says to only use todo for tasks I expect to take 5 or more steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  ask-user-question: 1,258 → 215
&lt;/h3&gt;

&lt;p&gt;This one is also by juicesharp: &lt;a href="https://github.com/juicesharp/rpiv-mono" rel="noopener noreferrer"&gt;&lt;code&gt;rpiv-ask-user-question&lt;/code&gt;&lt;/a&gt;. It lets the model ask you multiple-choice questions, and it's really handy.&lt;/p&gt;

&lt;p&gt;The wildest part is that a single UI detail gets explained five times. The detail: the UI automatically adds a "Type something." row under every question so you can type your own answer, which means the model shouldn't add its own "Other" option. Take a look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmhp7wp2vdn8s1fkh7r1g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmhp7wp2vdn8s1fkh7r1g.png" alt="rpiv-ask-user-question upstream vs lean: upstream mentions the " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mixed in there is also a note that while you're typing, this row expands to the full width of the pane so it isn't squeezed into the narrow options column. That's a UI note for humans. Knowing it doesn't change how the model writes questions.&lt;/p&gt;

&lt;p&gt;Length and count limits like &lt;code&gt;MAX 60 CHARACTERS&lt;/code&gt; are spelled out in prose too, even though the schema already enforces them with &lt;code&gt;maxLength&lt;/code&gt;, &lt;code&gt;minItems&lt;/code&gt;, and &lt;code&gt;maxItems&lt;/code&gt;. If the model goes over, validation rejects it anyway.&lt;/p&gt;

&lt;p&gt;At the end of the tool description there's also a long section on how previews render: monospace font, split view, options on the left and preview on the right... Again, that's all for humans.&lt;/p&gt;

&lt;p&gt;My lean version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Tool description
Ask 1-4 structured questions when a required user decision is unclear.

# Rules (just one)
Each question needs 2-4 options. Put recommendations first with (Recommended);
never add Other or Type something. Use multiSelect only for nonexclusive choices
and preview only for useful single-select visual comparisons.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I kept everything that actually affects how the model asks questions: how many options, put the recommended one first, don't add Other yourself, when to use multi-select, and when to add a preview. Everything else is either already handled by the schema or was never meant for the model in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity doesn't disappear, it just moves
&lt;/h3&gt;

&lt;p&gt;At this point I was reminded of something from software engineering called Tesler's Law: complexity can't be removed, only moved.&lt;/p&gt;

&lt;p&gt;A wordy prompt is really just complexity pushed onto the model. On every request, it has to reread all those rules and remember them. Move that into code, and the author writes it once and never has to think about it again.&lt;/p&gt;

&lt;p&gt;Of course, not everything can be moved. I sort it into three buckets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If code can decide it, let code handle it.&lt;/strong&gt; Types, enums, and lengths go in the schema. If a parameter is missing but can be inferred, the code fills it in. If something's wrong, validation rejects it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If only the model can decide it, keep it in the prompt, but keep it short.&lt;/strong&gt; Things like when to use the tool, or putting the recommended option first. Code can't make those calls, so one clear sentence is enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If it's rarely used, move it out of the way and look it up when needed.&lt;/strong&gt; That's the &lt;code&gt;help&lt;/code&gt; op I'll get to below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more thing I realized: error messages are prompts that only show up when needed. A rule in the prompt costs you on every request. An error only appears when the model actually gets something wrong, and it shows up at exactly the moment the model needs it. So instead of writing "label must be 60 characters or fewer" in the prompt, just have validation reply "label is over 60 characters, shorten it."&lt;/p&gt;

&lt;p&gt;That said, fallbacks need some restraint: only guess when the guess can't be wrong. Like in todo, an &lt;code&gt;id&lt;/code&gt; plus fields to change can only mean update. If it's ambiguous, don't guess. A clear error beats a wrong guess that quietly runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  If you write extensions
&lt;/h3&gt;

&lt;p&gt;Once you've written your tool descriptions, run through these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the same sentence show up once in the tool description, once in the rules, and once in a parameter description?&lt;/li&gt;
&lt;li&gt;Are enums, lengths, or counts already in the schema also written out in prose?&lt;/li&gt;
&lt;li&gt;Is there any UI description that helps humans but not the model?&lt;/li&gt;
&lt;li&gt;Is there any strong language like MUST, NEVER, or all caps?&lt;/li&gt;
&lt;li&gt;Did you hardcode something the user should decide?&lt;/li&gt;
&lt;li&gt;For mistakes the model makes often, could code catch them instead of the prompt repeating warnings?&lt;/li&gt;
&lt;li&gt;Are rarely used tools merged behind one entry point? (Method 2)&lt;/li&gt;
&lt;li&gt;Does the tool list stay the same for the whole session? (Method 3)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Method 2: Merge tools, and don't put rarely used ones front and center
&lt;/h2&gt;

&lt;p&gt;Shorter descriptions save some tokens, but the bigger cost is usually having too many tools. Every extra tool brings its own name, description, and schema.&lt;/p&gt;

&lt;h3&gt;
  
  
  subagent: 8,540 → 268
&lt;/h3&gt;

&lt;p&gt;tintinweb's &lt;a href="https://github.com/tintinweb/pi-subagents" rel="noopener noreferrer"&gt;&lt;code&gt;pi-subagents&lt;/code&gt;&lt;/a&gt; registers 4 tools, and &lt;code&gt;SubagentWorkflow&lt;/code&gt; alone takes 5,611 tokens. pi-web-access, which I'll get to next, has the same shape:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F020ykcymi7r7msdv0mxt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F020ykcymi7r7msdv0mxt.png" alt="Merging tools: pi-subagents' 4 tools become one subagent tool (8,540 to 268 tokens), and pi-web-access' 4 tools become one web_access tool (2,953 to 152 tokens)" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I merged all 4 into a single &lt;code&gt;subagent&lt;/code&gt; tool, with an &lt;code&gt;op&lt;/code&gt; parameter to choose between &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;result&lt;/code&gt;, &lt;code&gt;steer&lt;/code&gt;, &lt;code&gt;workflow&lt;/code&gt;, and &lt;code&gt;help&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;subagent: Run or inspect subagents/workflows through one tool;
use help for advanced parameters.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most common parameters (the task, a label, which kind of subagent, whether to run it in the background) go right in the schema. Rarely used advanced options get passed in a JSON string. If the model really needs those advanced options, it calls &lt;code&gt;op: help&lt;/code&gt; once and gets the full upstream docs.&lt;/p&gt;

&lt;p&gt;I didn't touch a single line of the subagent logic. All I changed was the entry point the model sees.&lt;/p&gt;

&lt;h3&gt;
  
  
  web access: 2,953 → 152
&lt;/h3&gt;

&lt;p&gt;Nico Bailon's &lt;a href="https://github.com/nicobailon/pi-web-access" rel="noopener noreferrer"&gt;&lt;code&gt;pi-web-access&lt;/code&gt;&lt;/a&gt; also has 4 tools: &lt;code&gt;web_search&lt;/code&gt;, &lt;code&gt;source_check&lt;/code&gt;, &lt;code&gt;fetch_content&lt;/code&gt;, and &lt;code&gt;get_search_content&lt;/code&gt;. With all of them enabled, that's 2,953 tokens. I merged them into one &lt;code&gt;web_access&lt;/code&gt; tool too, using &lt;code&gt;op&lt;/code&gt; for search, fact-checking, fetching pages, and retrieving results, with advanced parameters behind &lt;code&gt;help&lt;/code&gt;. It stays loaded the whole time and only costs 152 tokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I think this is fine
&lt;/h3&gt;

&lt;p&gt;Put simply: keep the stuff you use often in plain sight, and put the rest in the back where you can dig it out when needed. The cost is one extra &lt;code&gt;help&lt;/code&gt; call when the model needs an obscure feature. What you get back is those tokens saved on every single request. The less a feature gets used, the better the trade.&lt;/p&gt;

&lt;p&gt;Anthropic's &lt;a href="https://www.anthropic.com/engineering/writing-tools-for-agents" rel="noopener noreferrer"&gt;Writing effective tools for AI agents&lt;/a&gt; makes the same point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;More tools don't always lead to better outcomes.&lt;/p&gt;

&lt;p&gt;Too many tools or overlapping tools can also distract agents from pursuing efficient strategies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the context engineering article I mentioned earlier puts it even more bluntly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a human engineer can't definitively say which tool should be used in a given situation, an AI agent can't be expected to do better.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If a person can't tell which tool to use, don't expect the model to pick the right one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 3: Once the tool list is set, leave it alone
&lt;/h2&gt;

&lt;p&gt;When people hear "don't keep rarely used tools loaded all the time," a common first reaction is: fine, just add them when they're needed.&lt;/p&gt;

&lt;p&gt;That's exactly what the pi-web-access author did. Since version 0.31, it only loads a tiny &lt;code&gt;web_enable&lt;/code&gt; tool at startup. When the model wants to go online, it calls that first, which then turns on the other 4 tools. That does save tokens at startup, but turning them on usually costs more.&lt;/p&gt;

&lt;p&gt;The problem is prompt caching. Most providers cache by prefix match, and tool definitions usually sit at the very start of the request. Change the tool list mid-conversation and the prefix no longer matches, so the whole cached context before it gets billed again at full price. The longer the conversation, the more that one switch costs you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmvlfev2if4jvvowg1qsm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmvlfev2if4jvvowg1qsm.png" alt="Prompt cache: with a stable tool list everything before the new turn is a cache hit; when web_enable adds 4 tools on turn 4, the prefix changes at the first block and the whole context is billed again" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Pi 0.87, only providers that explicitly declare support will append new tools later in the conversation. Everywhere else, the tool list at the top of the request gets rewritten. So my lean version simply blocks &lt;code&gt;web_enable&lt;/code&gt; and doesn't let upstream switch tools mid-session. &lt;code&gt;web_access&lt;/code&gt; stays loaded from start to finish. At 152 tokens, keeping it loaded doesn't hurt.&lt;/p&gt;

&lt;p&gt;So if you want to save tokens on rarely used tools, my advice is to use Method 2: merge them into one tool instead of adding and removing tools mid-conversation.&lt;/p&gt;

&lt;p&gt;Pi itself has a similar situation. By default, the system prompt includes a section about Pi's own docs (a few hundred tokens), but you only need it when you're asking about Pi itself. Rob Zolkos made &lt;a href="https://github.com/robzolkos/pi-slim" rel="noopener noreferrer"&gt;pi-slim&lt;/a&gt;, which removes that section normally and brings it back with &lt;code&gt;/pi&lt;/code&gt; when you want it, without touching the tool list at all. The original no longer works on Pi 0.87.1, so I forked it and fixed it as &lt;a href="https://github.com/kunkun9527/pi-docs-slim" rel="noopener noreferrer"&gt;pi-docs-slim&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  That said, weaker models still need more guidance
&lt;/h2&gt;

&lt;p&gt;Everything above is about today's strongest models. If you're using a weaker model or running a local one, more detailed prompts are still the safer bet. Anthropic's article leaves room for this too:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that minimal does not necessarily mean short.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lean doesn't mean as short as possible.&lt;/p&gt;

&lt;p&gt;I happen to have an example of this. &lt;a href="https://github.com/ranxianglei/billion-context-pi" rel="noopener noreferrer"&gt;billion-context-pi&lt;/a&gt; is a context management extension that compresses earlier parts of the conversation into summaries and pulls the details back when needed. I'd made a lean prompt version for it too. When the author, ranxianglei, saw it, he merged it straight into the official version. In his words, he "kept 90%" of it, and turned it into a built-in prompt pack called &lt;code&gt;lean&lt;/code&gt;. You turn it on with one line of config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"compress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"promptPack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lean"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;He also deliberately kept one extra &lt;code&gt;howToCompress&lt;/code&gt; rule in the system prompt. In his words, it "fixed some model compression hallucination issues," which basically means some models make things up when they compress a conversation.&lt;/p&gt;

&lt;p&gt;I think that's exactly the right call: strong models get by with the short version, and weaker models still get the few lines they need. Now that the official version exists, I've stopped maintaining my own.&lt;/p&gt;




&lt;h2&gt;
  
  
  Make your own lean version
&lt;/h2&gt;

&lt;p&gt;I might not have a lean version of the extensions you use. That's fine, because this is a job you can hand to an agent.&lt;/p&gt;

&lt;p&gt;My approach is simple: create a new package, install the upstream extension as a dependency, and wrap it. When upstream registers its tools, the wrapper catches them first, swaps in the trimmed descriptions and schemas, and then registers them. When a tool actually runs, it still calls the original upstream code. No upstream code gets copied, and &lt;code&gt;node_modules&lt;/code&gt; stays untouched.&lt;/p&gt;

&lt;p&gt;Here are two prompts, one for building a lean version and one for maintaining it. Swap in the package names and send them to your agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a lean version
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Make a lean version of the Pi extension &amp;lt;upstream package&amp;gt;, named &amp;lt;upstream package&amp;gt;-lean.

Goal: keep every feature exactly the same as upstream. Only shorten the tool descriptions and schemas the model reads on every request.

Steps:
1. Install upstream as a dependency and pin the version. Don't copy upstream code, and don't modify node_modules.
2. Read upstream first. List every tool it registers: its description, promptSnippet, promptGuidelines, and parameter schema, plus how many characters each one takes.
3. Wrap the pi object passed to upstream in a Proxy. Intercept registerTool, collect the upstream tools, swap in the lean descriptions and schemas, then register them. execute calls upstream directly.
4. Trimming rules:
   - Say each thing once.
   - Don't repeat types, enums, lengths, or counts in prose if the schema already expresses them.
   - Remove parameter descriptions but keep field names, types, and constraints. Only keep a short description when a field name doesn't make its purpose clear.
   - Remove UI notes that only matter to humans.
   - Don't use MUST, NEVER, or all caps.
   - Don't hardcode things the user should decide, like "only use this for N+ steps."
   - Keep any rule that affects how the model calls the tool.
5. If upstream has several tools, especially rarely used ones, merge them into one tool: use an op parameter to choose the operation, put common parameters in the schema, and pass rare ones as a JSON string. Add op: help, which returns the full upstream description and parameters for the matching tool.
6. The tool list must not change mid-session. If upstream calls setActiveTools, or has a loader tool that turns on other tools when called, block it.
7. For call mistakes the model makes often, fill in the missing piece in code before validation, but only when the guess can't be wrong. If it's ambiguous, return a clear error.
8. Write tests: every tool or op reaches upstream, help returns the full parameters, the fill-in logic doesn't misfire, and the tool list can't change mid-session.
9. Measure how many tokens the upstream and lean tools each take, and put the numbers in the README. At the top of the README, say which project this is based on and who the original author is, and keep the original license.
10. Write a MAINTENANCE.md covering: the matching upstream version, what was trimmed in each tool, which upstream internals this depends on (tool names, validation order, loader tools, and so on), and how to upgrade.

Before you start building, show me the upstream tool list and how you plan to trim it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last line, "show me first," really matters. Agents sometimes get it wrong about which rules can go and which tools should be merged. Checking the plan up front saves a lot more time than redoing the work later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keeping up with upstream
&lt;/h3&gt;

&lt;p&gt;The real work with a lean version is maintenance: every time upstream ships a new version, you have to follow along. I pin the upstream version so nothing upgrades automatically, and I go through each update by hand. The process is pretty much always the same, so you can hand it to an agent too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sync &amp;lt;lean package&amp;gt; to the latest version of upstream &amp;lt;upstream package&amp;gt;.

1. Read MAINTENANCE.md first to understand the current upstream version and adaptation points.
2. Check the latest upstream version. Compare the code and changelog between the two versions, and list: added or removed tools, changes to parameters and defaults, behavior changes, and whether the internals recorded in MAINTENANCE.md still hold.
3. If only the version number changed and the code didn't, just upgrade the dependency.
4. For new parameters or tools, add them to the lean version using the same trimming rules: common ones go in the schema, rare ones go in help. If upstream changed behavior, update the descriptions so they still match what the tool does.
5. Run the tests, re-measure the tokens, and update the README and MAINTENANCE.md.
6. Summarize the changes for me, and only publish after I confirm.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how I maintain my own lean versions. Most upstream updates only change internal logic, so upgrading the dependency is all it takes. When I do have to change the adapter code, it's usually because upstream changed a tool name or parameters.&lt;/p&gt;




&lt;h2&gt;
  
  
  Thanks to these authors
&lt;/h2&gt;

&lt;p&gt;At the end of the day, my lean versions are just a wrapper around the original extensions. All the real work is done by code the original authors wrote. Thank you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;juicesharp: &lt;a href="https://github.com/juicesharp/rpiv-mono" rel="noopener noreferrer"&gt;rpiv-todo and rpiv-ask-user-question&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;tintinweb: &lt;a href="https://github.com/tintinweb/pi-subagents" rel="noopener noreferrer"&gt;pi-subagents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nico Bailon: &lt;a href="https://github.com/nicobailon/pi-web-access" rel="noopener noreferrer"&gt;pi-web-access&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;YuGiMob: &lt;a href="https://github.com/YuGiMob/pi-hashline-edit-pro" rel="noopener noreferrer"&gt;pi-hashline-edit-pro&lt;/a&gt;, along with its predecessor, RimuruW's &lt;a href="https://github.com/RimuruW/pi-hashline-edit" rel="noopener noreferrer"&gt;pi-hashline-edit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Rob Zolkos: &lt;a href="https://github.com/robzolkos/pi-slim" rel="noopener noreferrer"&gt;pi-slim&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ranxianglei: &lt;a href="https://github.com/ranxianglei/billion-context-pi" rel="noopener noreferrer"&gt;billion-context-pi&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're the author of one of these extensions and you like any of these changes, feel free to take them. billion-context-pi already shows it works: offering the lean version as an option inside the original is totally doable.&lt;/p&gt;




&lt;h2&gt;
  
  
  My setup
&lt;/h2&gt;

&lt;p&gt;My whole setup lives in &lt;a href="https://github.com/kunkun9527/my-lean-pi-setup" rel="noopener noreferrer"&gt;my-lean-pi-setup&lt;/a&gt;. I handle each part of the context separately:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;What I use&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tool descriptions&lt;/td&gt;
&lt;td&gt;The 5 lean extensions&lt;/td&gt;
&lt;td&gt;What this whole post is about&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code editing&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pi-hashline-edit-pro-lean&lt;/code&gt; (one of the 5 above)&lt;/td&gt;
&lt;td&gt;Edits by anchor, so no copying old code and no rereading after edits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base prompt&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pi-docs-slim&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes the Pi docs section included by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Command output&lt;/td&gt;
&lt;td&gt;RTK + &lt;code&gt;pi-rtk-optimizer&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Filters long terminal output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current context&lt;/td&gt;
&lt;td&gt;Headroom / noheadroom&lt;/td&gt;
&lt;td&gt;Compresses live tool output and conversation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conversation history&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;billion-context-pi&lt;/code&gt; (official, with &lt;code&gt;lean&lt;/code&gt; on)&lt;/td&gt;
&lt;td&gt;Compresses old conversation into summaries and retrieves details when needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Usage&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pi-context-view&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shows how many tokens each part takes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I want to give &lt;code&gt;pi-hashline-edit-pro&lt;/code&gt; a special shout-out here. I haven't said much about it yet, but I use it every day.&lt;/p&gt;

&lt;p&gt;It replaces Pi's built-in &lt;code&gt;edit&lt;/code&gt; with a set of anchor-based editing tools. When &lt;code&gt;read&lt;/code&gt; loads a file, every line gets a 4-letter anchor. To edit code, the model just says "replace everything from this anchor to that anchor with these lines."&lt;/p&gt;

&lt;p&gt;The token savings come on the output side. With the original &lt;code&gt;edit&lt;/code&gt; tool, the model first has to output the old code (old text) exactly as written, then output the new code (new text). If you're changing a big chunk of code, you have to copy that whole chunk first. hashline uses anchors to find the spot, so the model only gives the start and end anchors and then outputs the new code.&lt;/p&gt;

&lt;p&gt;The trade-off is that every line from &lt;code&gt;read&lt;/code&gt; now carries an anchor, so input tokens go up a little. But output tokens usually cost several times more than input. Spend a little more on input, save a big chunk of output, and on price it's clearly worth it.&lt;/p&gt;

&lt;p&gt;The anchors are also checked. If the file changed in the meantime, it refuses to write instead of editing the wrong spot. And if an edit does go wrong, you can undo it in one step.&lt;/p&gt;

&lt;p&gt;Upstream is YuGiMob's &lt;a href="https://github.com/YuGiMob/pi-hashline-edit-pro" rel="noopener noreferrer"&gt;pi-hashline-edit-pro&lt;/a&gt;. My lean version uses the same approach as the others: anchor validation, batch edits, undo, and everything else come straight from upstream. I only shortened the descriptions of the 5 tools and removed the parameter descriptions, taking it from 2,040 to 537 tokens. The tool descriptions only keep the few things the model gets wrong most often: copy anchors from &lt;code&gt;read&lt;/code&gt; output instead of making them up, and &lt;code&gt;replacement_lines&lt;/code&gt; is one string per line, with &lt;code&gt;[]&lt;/code&gt; meaning delete.&lt;/p&gt;

&lt;p&gt;Here's how to install the 5 lean extensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pi &lt;span class="nb"&gt;install &lt;/span&gt;npm:@ssk_dev/pi-web-access-lean
pi &lt;span class="nb"&gt;install &lt;/span&gt;npm:@ssk_dev/rpiv-todo-lean
pi &lt;span class="nb"&gt;install &lt;/span&gt;npm:@ssk_dev/rpiv-ask-user-question-lean
pi &lt;span class="nb"&gt;install &lt;/span&gt;npm:@ssk_dev/pi-subagents-lean
pi &lt;span class="nb"&gt;install &lt;/span&gt;npm:pi-hashline-edit-pro-lean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'd install &lt;code&gt;pi-context-view&lt;/code&gt; first and use &lt;code&gt;/context&lt;/code&gt; to see where your tokens are going right now. Then switch to the lean versions one at a time and compare before and after.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>piagent</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
