<?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: چودھری یاسر علی</title>
    <description>The latest articles on DEV Community by چودھری یاسر علی (@dhondooo).</description>
    <link>https://dev.to/dhondooo</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%2F954303%2Fb7730d42-1ad5-4953-a5a9-0970559acfed.jpg</url>
      <title>DEV Community: چودھری یاسر علی</title>
      <link>https://dev.to/dhondooo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dhondooo"/>
    <language>en</language>
    <item>
      <title>My CLAUDE.md was 48,000 tokens. I cut it to 4,400 — and then measured whether that broke anything.</title>
      <dc:creator>چودھری یاسر علی</dc:creator>
      <pubDate>Tue, 15 Sep 2026 17:20:46 +0000</pubDate>
      <link>https://dev.to/dhondooo/my-claudemd-was-48000-tokens-i-cut-it-to-4400-and-then-measured-whether-that-broke-anything-pho</link>
      <guid>https://dev.to/dhondooo/my-claudemd-was-48000-tokens-i-cut-it-to-4400-and-then-measured-whether-that-broke-anything-pho</guid>
      <description>&lt;p&gt;Every session in my repo started by loading a 194,492-character &lt;code&gt;CLAUDE.md&lt;/code&gt;. That is roughly &lt;strong&gt;48,600 tokens, on every single message&lt;/strong&gt;, and about 4.9× the size at which Claude Code starts warning you about a memory file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This guide and the accompanying scripts were generated with&lt;br&gt;
the assistance of AI. The workflow was tested end-to-end on one real&lt;br&gt;
repository and the numbers quoted throughout are from that run, but every&lt;br&gt;
codebase differs — please read and double-check all terminal commands and&lt;br&gt;
scripts before running them on your own system.&lt;/p&gt;

&lt;p&gt;Two things worth knowing before you start. &lt;strong&gt;The restructure rewrites&lt;br&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt; in place&lt;/strong&gt; and creates files under &lt;code&gt;.claude/&lt;/code&gt; — commit or back up&lt;br&gt;
first so you can &lt;code&gt;git checkout&lt;/code&gt; your way out. &lt;strong&gt;The measurement harness&lt;br&gt;
launches real headless Claude Code sessions&lt;/strong&gt;, one per prompt, which consume&lt;br&gt;
API quota and can take several minutes each; start with two or three prompts&lt;br&gt;
before running twenty.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;None of it was junk. It was two years of hard-won operational memory: the migration command that silently deletes an index, the seat index that retries the same seat forever, the colour function that serialises to a syntax both our contrast checkers were blind to. Deleting it was not an option.&lt;/p&gt;

&lt;p&gt;I got it to &lt;strong&gt;17,283 characters — a 91% reduction — with four words lost, all of them from headings I deleted on purpose.&lt;/strong&gt; Then I measured whether the restructure actually worked, which turned out to be the most useful part and the part nobody writes about.&lt;/p&gt;

&lt;p&gt;Here is the whole method, including the mistake I made halfway through.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the obvious fixes are wrong
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"Just delete the stale bits."&lt;/strong&gt; You cannot know which bits are stale without re-reading the code each one describes. "This trap looks obsolete" is a guess, and a wrong guess deletes the one note that would have saved the next debugging session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Summarise it."&lt;/strong&gt; This is the dangerous one, and I will come back to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Use &lt;code&gt;@import&lt;/code&gt; to split it up."&lt;/strong&gt; Imports expand inline. You get a tidier file and identical context cost.&lt;/p&gt;

&lt;p&gt;The actual problem is not that the file is big. It is that &lt;strong&gt;all of it loads for all of it&lt;/strong&gt;, including the 90% irrelevant to whatever you are doing right now. A CSS bug does not need the Stripe webhook ordering rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three layers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Holds&lt;/th&gt;
&lt;th&gt;Loads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commands, and rules true in &lt;strong&gt;every&lt;/strong&gt; session&lt;/td&gt;
&lt;td&gt;Always&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.claude/skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One topic — an index if large&lt;/td&gt;
&lt;td&gt;When its description matches the task&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.claude/skills/&amp;lt;name&amp;gt;/references/*.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The detail behind one part of a skill&lt;/td&gt;
&lt;td&gt;When the skill reads it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is a fourth, underused mechanism: &lt;strong&gt;&lt;code&gt;.claude/rules/*.md&lt;/code&gt; with &lt;code&gt;paths:&lt;/code&gt; frontmatter&lt;/strong&gt;, which loads by glob match on the files you touch. No model judgment involved — if the path matches, it loads.&lt;/p&gt;

&lt;p&gt;I ended with a 17KB &lt;code&gt;CLAUDE.md&lt;/code&gt;, 12 skills, and 28 reference files.&lt;/p&gt;




&lt;h2&gt;
  
  
  What stays resident: the stakes test
&lt;/h2&gt;

&lt;p&gt;A skill loads when the model judges its description relevant. That judgment is very good, but it is a judgment. So the test is not "is this important?" — everything in the file was important. The test is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If this rule failed to load exactly when it mattered, how bad is that?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A styling trap: you lose some time. A security rule: you ship the bug it exists to prevent.&lt;/p&gt;

&lt;p&gt;So in my file, every security rule stayed resident — all 26 of them — along with 21 architectural invariants (one database per tenant, the append-only ledger, the partial unique index arbitrating seat contention) and the commands, which are needed constantly and are cheap.&lt;/p&gt;

&lt;p&gt;Everything else — fees, booking, notifications, the mobile apps, the rendered pages, the test practices, the known-gaps list — moved.&lt;/p&gt;




&lt;h2&gt;
  
  
  The rule that matters most: extract, never paraphrase
&lt;/h2&gt;

&lt;p&gt;To state 47 rules in a ~200-line file, the obvious move is to rewrite each into a crisp one-liner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not do this.&lt;/strong&gt; My own repo's guidance, written by past-me after getting burned, says it better than I can:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A stale claim that gets edited without being checked is laundered, not corrected. Re-read the code the line describes, or leave the line alone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Paraphrasing 47 rules I had not re-verified would produce 47 confident-sounding claims nobody checked — and they would look &lt;em&gt;freshly reviewed&lt;/em&gt;, which is worse than being obviously old.&lt;/p&gt;

&lt;p&gt;The way out: &lt;strong&gt;your rules are probably already written with the rule as the opening sentence.&lt;/strong&gt; Mine were. So lift that sentence &lt;strong&gt;verbatim&lt;/strong&gt; and move the reasoning to a reference file. Nothing is rewritten. The rule sits in &lt;code&gt;CLAUDE.md&lt;/code&gt;; the "why" sits one hop away.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- **The card never touches this server.** A SetupIntent hands the browser a
  client secret and Stripe's own SDK collects the number, which is why no
  endpoint here takes one.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One sentence resident. The remaining 400 words of reasoning in &lt;code&gt;hard-rules/references/security.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two of my entries opened with a &lt;em&gt;finding&lt;/em&gt; rather than an instruction ("A capital letter moved an anonymous crawler onto a studio's members' rate bucket"). Both happened to end with the author's own "The general rule: …" sentence. I carried that too — still their words, not mine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prove you did not lose anything
&lt;/h2&gt;

&lt;p&gt;Line-by-line diffing is useless: moving prose re-wraps it, so every line reads as changed. Sentence matching is nearly as bad, because bold markers and headings shift the boundaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Word multisets are immune to both.&lt;/strong&gt; Every word of the original must still appear, at least as many times, somewhere in the new corpus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="n"&gt;WORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[A-Za-z0-9_./:%-]+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_new_text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;lost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My final run: &lt;strong&gt;4 of 31,697 word occurrences missing&lt;/strong&gt; — &lt;code&gt;Traps&lt;/code&gt;, &lt;code&gt;bitten&lt;/code&gt;, &lt;code&gt;Invariants&lt;/code&gt;, &lt;code&gt;simplify&lt;/code&gt;. All four from the two section headings I deleted. That is what done looks like.&lt;/p&gt;

&lt;p&gt;And check that it &lt;em&gt;fails&lt;/em&gt; when it should. I deleted one skill directory and re-ran: 2,522 losses, including the word &lt;code&gt;fee&lt;/code&gt; forty times. A verification you have never seen fail is not a verification.&lt;/p&gt;




&lt;h2&gt;
  
  
  The mistake I made
&lt;/h2&gt;

&lt;p&gt;My build script &lt;em&gt;appended&lt;/em&gt; the moved entries to two existing skill files. I ran it twice while iterating.&lt;/p&gt;

&lt;p&gt;Result: 36 entry blocks where 28 belonged. Silent duplication — the exact failure mode every guide on this warns about, and I walked into it anyway while writing about avoiding it.&lt;/p&gt;

&lt;p&gt;It was caught only because I counted each entry across every file and asserted it appeared exactly once. &lt;strong&gt;Add that check.&lt;/strong&gt; Make your build script idempotent, or have it rewrite files rather than append to them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Now measure it — do not trust the number you read
&lt;/h2&gt;

&lt;p&gt;Here is where I diverge from the other write-ups.&lt;/p&gt;

&lt;p&gt;A widely-shared figure says skill activation runs around &lt;strong&gt;79%&lt;/strong&gt; versus 100% for a rule sitting directly in &lt;code&gt;CLAUDE.md&lt;/code&gt;. That is a genuinely useful warning, and it is also &lt;strong&gt;one person's measurement of their own configuration&lt;/strong&gt;. It is not a constant. I had been repeating it as if it were.&lt;/p&gt;

&lt;p&gt;So I measured mine. The method:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write 14 prompts a real user would type, spread across all the skills, phrased as &lt;em&gt;symptoms&lt;/em&gt; rather than topics. "The Booked screen crashes with RangeError" — not "tell me about the mobile app", which names the answer for you.&lt;/li&gt;
&lt;li&gt;Run each in a &lt;strong&gt;fresh headless session&lt;/strong&gt; (&lt;code&gt;claude -p&lt;/code&gt;). The session doing the restructure already has every skill in context; asking it "would you have loaded this?" measures nothing.&lt;/li&gt;
&lt;li&gt;Capture each run's own &lt;code&gt;session_id&lt;/code&gt; via &lt;code&gt;--output-format json&lt;/code&gt; so probes can run in parallel without being confused with each other.&lt;/li&gt;
&lt;li&gt;Read that session's transcript and record which skills loaded.&lt;/li&gt;
&lt;li&gt;Block &lt;code&gt;Edit&lt;/code&gt;/&lt;code&gt;Write&lt;/code&gt; so the measurement cannot modify the repo it measures.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Count &lt;strong&gt;two&lt;/strong&gt; signals, not one: the &lt;code&gt;Skill&lt;/code&gt; tool firing, &lt;em&gt;and&lt;/em&gt; the model reading a skill file directly. Reaching the right knowledge by opening the file is a hit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result: 13 of 14 — 93%.&lt;/strong&gt; Not 79%. And on every single hit, the skill fired as &lt;strong&gt;tool call #1&lt;/strong&gt;, before any file was opened.&lt;/p&gt;




&lt;h2&gt;
  
  
  The most useful finding: a miss is expensive, not wrong
&lt;/h2&gt;

&lt;p&gt;The one miss still produced a &lt;strong&gt;correct answer&lt;/strong&gt;. It just rebuilt it from scratch: &lt;strong&gt;56 tool calls, against a median of 16 on the hits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It re-read four source files and grepped the API to re-derive what the skill would have handed it in one read. Meanwhile the always-loaded layer acted as a safety net — a resident hard rule about calendar dates routed it to the right reference anyway.&lt;/p&gt;

&lt;p&gt;That reframes the whole risk. A miss is not "the rule does not get applied." It is a session that costs 3.5× more. That is a much less frightening failure mode, and I would never have known it from reading blog posts, including this one.&lt;/p&gt;




&lt;h2&gt;
  
  
  And the miss was a bug in my writing, not in the architecture
&lt;/h2&gt;

&lt;p&gt;Both mobile prompts hit the same skill. Only the one containing the word "Expo" fired.&lt;/p&gt;

&lt;p&gt;The skill's description advertised &lt;strong&gt;tooling&lt;/strong&gt;: &lt;em&gt;"SDK pinning against the Expo Go ceiling, Metro under pnpm, driving a simulator with idb."&lt;/em&gt; But the skill also held screen-level traps — a Book button offered on a class the member already holds, a crashing date field. The prompt &lt;em&gt;"the Booked screen crashes"&lt;/em&gt; matched none of the advertised words.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write descriptions that name symptoms, not tools.&lt;/strong&gt; What will the user actually &lt;em&gt;see&lt;/em&gt;?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ "pnpm settings, Node test globs, tsc output, Docker image layout"&lt;/li&gt;
&lt;li&gt;✅ "Use when a build fails for a reason that is not in the code — &lt;code&gt;MODULE_NOT_FOUND&lt;/code&gt;, a missing query engine, an image far bigger than expected, or a fix that only takes effect on the second run"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I rewrote all 11 descriptions this way and re-measured with seven fresh symptom-phrased prompts — the exact style that had failed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7 of 7, every one at tool call #1.&lt;/strong&gt; The prompt that previously missed now hits, in 26 tool calls instead of 56.&lt;/p&gt;




&lt;h2&gt;
  
  
  The second net: path-scoped rules
&lt;/h2&gt;

&lt;p&gt;For anything that maps onto a directory, &lt;code&gt;.claude/rules/*.md&lt;/code&gt; removes the judgment entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps/mobile/**"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps/mobile-yoga/**"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

You are in one of the two Expo member apps.

&lt;span class="gs"&gt;**Read `.claude/skills/mobile-apps/SKILL.md` before changing anything here.**&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep these as &lt;strong&gt;pointers, never copies&lt;/strong&gt; — the knowledge stays in exactly one place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify with a two-sided canary.&lt;/strong&gt; A scoped rule matching nothing looks identical to one that works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a rule with &lt;code&gt;paths: ["some/dir/**"]&lt;/code&gt; whose body says to emit a unique token.&lt;/li&gt;
&lt;li&gt;Probe a file &lt;strong&gt;inside&lt;/strong&gt; that directory — the token must appear.&lt;/li&gt;
&lt;li&gt;Probe a file &lt;strong&gt;outside&lt;/strong&gt; it — the token must &lt;strong&gt;not&lt;/strong&gt; appear.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 3 is the one people skip. Without it you cannot tell "works" from "always loaded", and the second silently undoes your savings. Mine passed both ways: 1 and 0.&lt;/p&gt;

&lt;p&gt;One warning: build the globs against your &lt;strong&gt;real&lt;/strong&gt; layout. I assumed &lt;code&gt;apps/api/src/fees/&lt;/code&gt;; the code actually keeps fees, memberships and class packs in &lt;code&gt;apps/api/src/billing/&lt;/code&gt;. Had I not checked, the rules would have matched nothing, silently, forever.&lt;/p&gt;




&lt;h2&gt;
  
  
  The honest costs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The corpus grew 14%&lt;/strong&gt; — 194,492 to 220,885 characters. That extra 26,393 is frontmatter, index tables and pointers. None of it is knowledge. It exists so the right file can find you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A change now lands in more places.&lt;/strong&gt; One file became three edits. More places to go stale. A routing table in &lt;code&gt;CLAUDE.md&lt;/code&gt; helps; it is a mitigation, not a guarantee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Occasional forgetfulness.&lt;/strong&gt; You trade "always slightly bloated" for "usually lean, occasionally expensive."&lt;/p&gt;

&lt;p&gt;I would make the trade again. But state it plainly rather than pretending the restructure is free.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;I packaged the method as a Claude Code plugin — two skills: one that performs the restructure with the safety rules baked in, one that measures whether your skills actually fire.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add dhondooo/claude-md-progressive-disclosure
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;progressive-claude-md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then just say: &lt;em&gt;"my CLAUDE.md is too big, restructure it"&lt;/em&gt;, and later, &lt;em&gt;"measure whether my skills actually fire."&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Credit where it is due
&lt;/h2&gt;

&lt;p&gt;The three-layer framing and the 79% activation warning come from &lt;a href="https://note.com/jolly_daphne9092/n/n5fc43e6541f0" rel="noopener noreferrer"&gt;a note.com post on progressive disclosure&lt;/a&gt;. The &lt;code&gt;&amp;lt;150&lt;/code&gt; line SKILL.md convention, the &lt;code&gt;references/&lt;/code&gt; layer and the "what becomes what" mapping are from &lt;a href="https://medium.com/@cem.karaca/my-claude-md-was-eating-42-000-tokens-per-conversation-heres-how-i-fixed-it-85ffba809bd4" rel="noopener noreferrer"&gt;cem.karaca's write-up&lt;/a&gt;. The memory tiers, &lt;code&gt;@import&lt;/code&gt; caveat and compression passes are from &lt;a href="https://medium.com/@bijit211987/the-complete-guide-to-claude-md-memory-rules-loading-and-cross-tool-compression-97cc12ed037b" rel="noopener noreferrer"&gt;bijit211987's guide&lt;/a&gt;. Shyam Verma's &lt;a href="https://shyamverma.com/stop-overfeeding-your-claude-md" rel="noopener noreferrer"&gt;"Stop overfeeding your CLAUDE.md"&lt;/a&gt; is where the "&amp;lt;50% of conversations → make it a skill" heuristic comes from.&lt;/p&gt;

&lt;p&gt;What I would add to all of them: &lt;strong&gt;measure your own hit rate before building anything to fix it.&lt;/strong&gt; Mine was 93% before I touched a thing, and the one real defect was a sentence I had written badly — not the architecture.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Effortlessly Manage Multiple Accounts in GitHub Desktop (macOS)</title>
      <dc:creator>چودھری یاسر علی</dc:creator>
      <pubDate>Thu, 05 Mar 2026 17:24:50 +0000</pubDate>
      <link>https://dev.to/dhondooo/how-to-effortlessly-manage-multiple-accounts-in-github-desktop-macos-41bd</link>
      <guid>https://dev.to/dhondooo/how-to-effortlessly-manage-multiple-accounts-in-github-desktop-macos-41bd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Disclaimer:&lt;/em&gt;&lt;/strong&gt; This guide and the accompanying scripts were generated with the assistance of AI. While the workflow has been tested, please double-check all terminal commands and scripts before running them on your own system&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you use GitHub Desktop, you probably love its clean UI and seamless conflict resolution. But if you are a freelancer, an agency developer, or just someone juggling personal and work repositories, you’ve definitely hit its biggest limitation: &lt;strong&gt;GitHub Desktop does not natively support multiple accounts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While there is a massive &lt;a href="https://github.com/desktop/desktop/issues/3707" rel="noopener noreferrer"&gt;official feature request for this&lt;/a&gt; that has been active for years, the maintainers unfortunately have it tagged as &lt;code&gt;not-planned&lt;/code&gt; for the foreseeable future.&lt;/p&gt;

&lt;p&gt;If you want to switch from your personal account to a client’s account, you have to manually sign out, sign back in, and re-configure your Git identity every single time.&lt;/p&gt;

&lt;p&gt;After getting frustrated with this, I built a fully automated terminal workflow for macOS that lets you swap GitHub Desktop profiles and Git identities in a split second using a single command.&lt;/p&gt;

&lt;p&gt;Here is how you can set it up.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Core Concept: The Symlink Trick
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;(Credit where credit is due: The foundational idea of swapping configuration folders via symlinks was inspired by&lt;/em&gt;&lt;a href="https://stackoverflow.com/a/79241563/7074839" rel="noopener noreferrer"&gt; &lt;em&gt;this clever Stack Overflow answer&lt;/em&gt;&lt;/a&gt; &lt;em&gt;. I’ve expanded on that concept here to include global Git identity swapping and a fully automated profile generation script.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;GitHub Desktop stores all of its session data, login tokens, and preferences in this directory: &lt;code&gt;~/Library/Application Support/GitHub Desktop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;By renaming this folder (e.g., to &lt;code&gt;GitHub Desktop.config1&lt;/code&gt;) and creating a symbolic link (symlink) in its place, we can trick the application into loading different profiles whenever we swap the symlink out.&lt;/p&gt;

&lt;p&gt;Even better, we can chain this with standard &lt;code&gt;git config&lt;/code&gt; commands so that your commits always use the correct email address for the active profile!&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: Add the Automation to Your &lt;code&gt;.zshrc&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Instead of doing this manually every time, we are going to add aliases and a smart bash function to your terminal configuration.&lt;/p&gt;

&lt;p&gt;Open your terminal and edit your zsh configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ~/.zshrc

&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# =========================================================  &lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# 1. GITHUB DESKTOP &amp;amp; GIT IDENTITY SWITCHERS  &lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# =========================================================  &lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gitpersonal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ln -nfs "$HOME/Library/Application Support/GitHub Desktop.config1" "$HOME/Library/Application Support/GitHub Desktop" &amp;amp;&amp;amp; git config --global user.name "Your Name" &amp;amp;&amp;amp; git config --global user.email "personal@email.com" &amp;amp;&amp;amp; echo "Switched to Personal Profile (Config 1)"'&lt;/span&gt;  
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gitwork&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ln -nfs "$HOME/Library/Application Support/GitHub Desktop.config2" "$HOME/Library/Application Support/GitHub Desktop" &amp;amp;&amp;amp; git config --global user.name "Work Name" &amp;amp;&amp;amp; git config --global user.email "work@company.com" &amp;amp;&amp;amp; echo "Switched to Work Profile (Config 2)"'&lt;/span&gt;  
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# =========================================================  &lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# 2. PROFILE MANAGEMENT AUTOMATION  &lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# =========================================================  &lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Command to un-link and prepare for a fresh login  &lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gitnew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'rm "$HOME/Library/Application Support/GitHub Desktop" &amp;amp;&amp;amp; echo "Delinked! Open GitHub Desktop to set up a fresh profile."'&lt;/span&gt;  
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Command to save a newly created profile and generate an alias automatically  &lt;/span&gt;
gitsave&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then  
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Usage: gitsave &amp;lt;alias_name&amp;gt; (e.g., gitsave gitclient)"&lt;/span&gt;  
    &lt;span class="k"&gt;return &lt;/span&gt;1  
  &lt;span class="k"&gt;fi  
  &lt;/span&gt;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;target_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Library/Application Support/GitHub Desktop"&lt;/span&gt;  

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$target_dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$target_dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then  
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: No fresh setup found. Run 'gitnew', log in, close app, and try again."&lt;/span&gt;  
    &lt;span class="k"&gt;return &lt;/span&gt;1  
  &lt;span class="k"&gt;fi  
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enter Git User Name for this profile (e.g., John Doe):"&lt;/span&gt;  
  &lt;span class="nb"&gt;read &lt;/span&gt;git_name  
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enter Git Email for this profile (e.g., john@example.com):"&lt;/span&gt;  
  &lt;span class="nb"&gt;read &lt;/span&gt;git_email  
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1  
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.config&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;num&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;  
    &lt;span class="o"&gt;((&lt;/span&gt;num++&lt;span class="o"&gt;))&lt;/span&gt;  
  &lt;span class="k"&gt;done  
  &lt;/span&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$target_dir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.config&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;num&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;  

  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;alias_cmd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"alias &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;='ln -nfs &lt;/span&gt;&lt;span class="se"&gt;\"\$&lt;/span&gt;&lt;span class="s2"&gt;HOME/Library/Application Support/GitHub Desktop.config&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;num&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"\$&lt;/span&gt;&lt;span class="s2"&gt;HOME/Library/Application Support/GitHub Desktop&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; git config --global user.name &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$git_name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; git config --global user.email &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$git_email&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Switched to (&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;) Config &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;num&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;  

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc  
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$alias_cmd&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc  

  &lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc  
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Saved current profile as config&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;num&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; and added alias '&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;' to .zshrc!"&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file (&lt;code&gt;Ctrl + O&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;, &lt;code&gt;Ctrl + X&lt;/code&gt;) and reload your terminal:&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;source&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 2: How to Use Your New Superpowers
&lt;/h1&gt;

&lt;p&gt;Now that the code is in place, managing your accounts is incredibly simple.&lt;/p&gt;

&lt;h1&gt;
  
  
  Switching Between Existing Profiles
&lt;/h1&gt;

&lt;p&gt;Ensure GitHub Desktop is &lt;strong&gt;closed&lt;/strong&gt;. Open your terminal and type your alias:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gitwork
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Boom.&lt;/em&gt; You are now logged into your work account, and any commits you make will automatically be attributed to your work email. Need to switch back? Close the app, type &lt;code&gt;gitpersonal&lt;/code&gt;, and you're done.&lt;/p&gt;

&lt;h1&gt;
  
  
  Adding a Brand New Profile (The Magic Workflow)
&lt;/h1&gt;

&lt;p&gt;This is where the &lt;code&gt;gitsave&lt;/code&gt; function shines. Let's say you just landed a new freelance client and need a dedicated GitHub account for them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Close GitHub Desktop&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;gitnew&lt;/code&gt; in your terminal. &lt;em&gt;(This safely unlinks your current profile).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open GitHub Desktop&lt;/strong&gt;. It will act like a brand-new installation! Log into your new client account and set up your preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Close GitHub Desktop&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Run your save command with whatever shortcut name you want to use:  &lt;code&gt;gitsave gitclient&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The terminal will ask you for the Git Name and Email you want to associate with this specific client.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The script will automatically move the folder to the next available slot (like &lt;code&gt;config3&lt;/code&gt;), dynamically write the new alias into your &lt;code&gt;.zshrc&lt;/code&gt; file, and reload your terminal. You can now type &lt;code&gt;gitclient&lt;/code&gt; anytime you want to work on their codebase!&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;Until GitHub officially supports multi-account management in their desktop client, this symlink trick is an absolute lifesaver. It keeps your identities perfectly separated and completely removes the friction of logging in and out.&lt;/p&gt;

&lt;p&gt;Let me know in the comments if this workflow helped you clean up your Git environment! 🚀&lt;/p&gt;

</description>
      <category>github</category>
      <category>git</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
