<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Claude on MangoDriod</title><link>https://md.eknath.dev/tags/claude/</link><description>Recent content in Claude on MangoDriod</description><generator>Hugo -- 0.141.0</generator><language>en-us</language><lastBuildDate>Sun, 26 Apr 2026 10:25:15 +0530</lastBuildDate><atom:link href="https://md.eknath.dev/tags/claude/index.xml" rel="self" type="application/rss+xml"/><item><title>AI Command Center to manage multiple projects [Expriment]</title><link>https://md.eknath.dev/posts/software-development/ai-command-center-expriment/</link><pubDate>Sun, 26 Apr 2026 10:25:15 +0530</pubDate><guid>https://md.eknath.dev/posts/software-development/ai-command-center-expriment/</guid><description>&lt;p>a team of 20+ handed over a project to our team of 5. i ended up owning all the native clients: iOS, Android, Windows by mostly bymyself. There are multiple repos, multiple languages and the hardship of understanding thier 7 year codebase.&lt;/p>
&lt;p>initially the thought of this was pretty stressful, but being a good solutionist i proceeded with dicecting the issues one by one and presistent on finding a solition for them all.&lt;/p></description><content:encoded><![CDATA[<p>a team of 20+ handed over a project to our team of 5. i ended up owning all the native clients: iOS, Android, Windows by mostly bymyself. There are multiple repos, multiple languages and the hardship of understanding thier 7 year codebase.</p>
<p>initially the thought of this was pretty stressful, but being a good solutionist i proceeded with dicecting the issues one by one and presistent on finding a solition for them all.</p>
<p>The first thing is prioritizing platoforms, The stats were clear hence shared them with my manager, got iOS, Android prioritized in order and parked Windows for later as usage is extremly low. now the priority is set to the next thing.</p>
<p>The problem was not the workload. it was the cognitive overhead. i can barely understand my own code after a few months. here i am inheriting code from 6-7 people who clearly took shortcuts to ship fast. folder structure was a dump. files everywhere. and on top of reverse-engineering three codebases i had to track what is done, what is next, what is blocked: simultaneously, across all platforms this task alone without AI would be a real pain and would def take more than few months.</p>
<p>I opted to the $20 Claude subscription. so every session i was wasting the first chunk of context re-explaining the same codebase to Claude, re-orienting it to where i left off, re-answering questions it should already know. by lunch i was running out of tokens i had to use my colleague&rsquo;s accounts to do whole thing again (Thanks Arun!)</p>
<p>out of this mess i needed a single place. one terminal. one browser tab. one AI session that already knows everything and picks up exactly where we left off, an interface for me and claude to read/update/learn about the project im working and it has to be highly structured, organized and prioritized.</p>
<p>so i built one. i call it the <strong>Command Center</strong>. if you have any other name to suggest, my inbox is open. this post is the full breakdown of what it is, how it works, and how you can shape it for your your own structure if you ever are in that spot, a little future pridction i think by the end of 2026 we all might have to work in this kind of set-up working on multiple projects simultaniously or atleast we will be capabble of that level of productivity.</p>
<hr>
<h2 id="what-is-this-ai-command-center">What is this AI-Command Center</h2>
<p><img alt="The Command Center&rsquo;s Dashboard Home Screen — This is the primary human interface rendered in the browser tab with everything: repo status, today&rsquo;s focus, quick links, docs and more" loading="lazy" src="/img/command-center-images/cce-home.png"></p>
<p>the idea is simple. instead of having our docs, tasks, changelogs in multiple apps and your terminal tabs scattered across screens for different platforms wokfing with different stages of the tasks or even totally different task altogether: and your daily runner claude-code has no means to know about all these instead you put a single shared operational layer above all your repos. not inside them. above them hence the term command center.</p>
<pre tabindex="0"><code>MyWorkspace/
├── ios/               ← own git repo, untouched
├── ios-dataKit/       ← own git repo, untouched
├── android/           ← own git repo, untouched
├── win/               ← own git repo, untouched
└── .ops/              ← Command Center (its own git repo)
    ├── docs/          ← documentation per project
    ├── todo/          ← task files per project + daily focus
    ├── memo/          ← decisions, KT notes, research
    ├── diagrams/      ← architecture diagrams + companion notes
    ├── changelog/     ← per-project ship history
    ├── scripts/       ← automation scripts
    └── dashboard/     ← local web dashboard
</code></pre><p>Don&rsquo;t worry the project folders stay completely independent. <code>git -C ios/ status</code> never bleeds into <code>git -C android/ status</code>. you can add or remove a project folder without touching anything else, this is very important sepearation for corporate repositories where the restrictions are tight.</p>
<p>almost everything in <code>.ops/</code> is a markdown, here is where it might looks like the WiKi pattern shared by the Andrej Karpathy. it is readable by me and the AI, diffs cleanly, and has zero dependencies you can stop here is you want a bare simple command-center but if you are like me this is not enough and there are many flaws here like doc&rsquo;s going stale as we make changes so lets get to the text stage.</p>
<hr>
<h2 id="the-scripts-are-the-real-mvp">The scripts are the real MVP</h2>
<p>As i said earlier i still use the 20$ subscription so for me tokens are really valuable running out of limit means one less productive day that might gift me a day of guilt so making use of scripts to save some routine commands that im sure will be helpful for claude to not be too dependent on remote calls, it might be confusting so here is example:</p>
<p>when i ask Claude &ldquo;what is the git status across all my repos?&rdquo;  Claude tries to figure it out by calling tools one at a time burning tokens on reasoning and multiple tool calls to give me accurate and proper response</p>
<p>but if you have a script that does it:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># .ops/scripts/git_status_all.sh</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> dir in android ios ios-dataKit ios-textEditor win; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    branch<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>git -C <span style="color:#e6db74">&#34;</span>$ROOT<span style="color:#e6db74">/</span>$dir<span style="color:#e6db74">&#34;</span> branch --show-current 2&gt;/dev/null<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>    changes<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>git -C <span style="color:#e6db74">&#34;</span>$ROOT<span style="color:#e6db74">/</span>$dir<span style="color:#e6db74">&#34;</span> status --porcelain | wc -l | tr -d <span style="color:#e6db74">&#39; &#39;</span><span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$changes<span style="color:#e6db74">&#34;</span> -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>        echo <span style="color:#e6db74">&#34;● </span>$dir<span style="color:#e6db74"> — </span>$branch<span style="color:#e6db74"> (</span>$changes<span style="color:#e6db74"> uncommitted)&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>        echo <span style="color:#e6db74">&#34;● </span>$dir<span style="color:#e6db74"> — </span>$branch<span style="color:#e6db74"> (clean)&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span></code></pre></div><p>Claude runs the script. gets the answer in one shot. no reasoning, no guessing, no tool call loop you don&rsquo;t have to write this manually you can just ask it to do, just make sure you get the code though.</p>
<p>the scripts i have accumulated up over time:</p>
<table>
  <thead>
      <tr>
          <th>Script</th>
          <th>What it does</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>briefing.sh</code></td>
          <td>morning snapshot: repo status, high-priority tasks, daily focus, doc staleness — all in one output</td>
      </tr>
      <tr>
          <td><code>session_context.sh</code></td>
          <td>generates a JSON briefing injected into Claude context at session start via a hook</td>
      </tr>
      <tr>
          <td><code>daily_reset.sh</code></td>
          <td>resets <code>daily.md</code> to today, carries over incomplete items, pulls high-priority tasks from project todos</td>
      </tr>
      <tr>
          <td><code>git_status_all.sh</code></td>
          <td>git status across all repos in one command</td>
      </tr>
      <tr>
          <td><code>git_pull_all.sh</code></td>
          <td>pull latest on all repos</td>
      </tr>
      <tr>
          <td><code>git_branch_all.sh</code></td>
          <td>current branch per repo</td>
      </tr>
      <tr>
          <td><code>doc_sync.js</code></td>
          <td>diffs each doc&rsquo;s last-verified commit against HEAD, flags stale docs</td>
      </tr>
      <tr>
          <td><code>pre-push-codecheck.sh</code></td>
          <td>pre-push validation — lint, build check, etc. per platform</td>
      </tr>
      <tr>
          <td><code>log_token_saving.py</code></td>
          <td>PostToolUse hook — logs each local MCP call with estimated tokens saved, reminds Claude to tag responses with <code>[local-command-center-mcp]</code></td>
      </tr>
  </tbody>
</table>
<p>the pattern is always same: take something that would require Claude to do many tool calls or make assumptions, turn it into one script, let Claude just run it and read the output. you get a more reliable answer and you spend a fraction of the tokens.</p>
<p>the <code>session_context.sh</code> one is worth explaining. it runs as a session-start hook and injects the project context automatically before i type anything:</p>
<pre tabindex="0"><code>=== SESSION BRIEFING (2026-04-26) ===

REPOS
  ios          dev_eganathan   clean
  android      dev_eganathan   clean
  ios-dataKit  dev_eganathan   14 uncommitted  ← needs attention

HIGH PRIORITY (ios)
  - sessionId hardcoded as &#34;&#34; (TIBConverseInteractor.swift:83)
  - Localization migration uncommitted

LAST SESSION: 2026-04-22 — ios folder restructure, Settings flatten done
DOC SYNC: 8 stale docs — run /sync
=====================================
</code></pre><p>this replaces re-explaining the codebase every session. the entire briefing is generated from actual file state and costs about 100 tokens to inject i shared only a small portion of this but it basically added more relavant contexts that im sure will help claude so compare that to the 500–1000 tokens you&rsquo;d spend manually orienting Claude each time.</p>
<hr>
<h2 id="documentation-that-doesnt-go-stale">Documentation that doesn&rsquo;t go stale</h2>
<p><img alt="Docs folder — each file has watches frontmatter so the sync script knows exactly which code changes make it stale." loading="lazy" src="/img/command-center-images/cce-doc-folder.png"></p>
<p>the biggest problem with docs is they go stale the moment you stop actively maintaining them. and the honest truth is most people stop maintaining them pretty quickly.</p>
<p>so instead of relying on discipline, i wired it into the workflow. every doc has frontmatter that declares what code it describes:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>---
</span></span><span style="display:flex;"><span><span style="color:#f92672">project</span>: <span style="color:#ae81ff">ios</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">watches</span>: <span style="color:#ae81ff">ios/Features/Inbox/**, ios/Core/Network/**</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">lastVerified</span>: <span style="color:#ae81ff">a3f9c12</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">verifiedDate</span>: <span style="color:#e6db74">2026-04-20</span>
</span></span><span style="display:flex;"><span>---
</span></span></code></pre></div><p><code>watches</code> is a glob pattern over source paths. <code>lastVerified</code> is the git commit hash when i last checked this doc.</p>
<p><code>doc_sync.js</code> runs at session start: diffs <code>lastVerified</code> against HEAD per project, filtered by <code>watches</code>. if watched files changed, the doc is flagged stale. you get a list of exactly which docs need attention — not all of them, just the ones where the underlying code actually changed.</p>
<p>the workflow: read the diff, update the doc if needed, run <code>--mark-current</code> to stamp it with the new HEAD. stale docs are a session-start action item, not a quarterly effort.</p>
<p>one more thing worth building: a <code>doc_sync_prompt.md</code> template. when <code>doc_sync.js</code> flags a doc as stale, you need to give Claude a consistent prompt for reviewing it. the template fills in <code>{{DOC_PATH}}</code>, <code>{{GIT_DIFF_STAT}}</code>, <code>{{CHANGED_FILES}}</code>, and <code>{{DOC_CONTENT}}</code> — Claude reads the diff, decides what changed, updates only what is wrong or outdated, and preserves the frontmatter format. without a template you end up writing a different prompt every time and the quality of the review varies. one template file in <code>scripts/</code>, referenced whenever <code>/sync</code> runs.</p>
<hr>
<h2 id="task-management-across-platforms">Task management across platforms</h2>
<p><img alt="Per-platform todo files with priority buckets — high, medium, low, and completed. Daily.md pulls from these each morning." loading="lazy" src="/img/command-center-images/cce-todos.png"></p>
<p>one file per platform. <code>ios_todos.md</code>, <code>android_todos.md</code>, <code>win_todos.md</code>. same structure in all of them:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span><span style="color:#75715e">## High Priority
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">- [ ]</span> Fix session ID bug in TIBConverseInteractor.swift:83
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Medium Priority
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">- [ ]</span> Add unit test target
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Low Priority
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">- [ ]</span> Refactor legacy auth flow
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Completed
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">- [x]</span> 2026-04-20 — Migrated Localizable strings
</span></span></code></pre></div><p>there is also <code>daily.md</code> — today&rsquo;s focus, separate from the long-running backlogs. <code>daily_reset.sh</code> resets it each morning, carries over anything incomplete from yesterday, and pulls the top items from each project&rsquo;s High Priority section so you are never starting from blank. at end of day you move done items back to the project file and carry over the rest.</p>
<p>it is not rocket science but it works because everything is in one place and Claude can read all of it directly — no context switching, no &ldquo;go check Linear&rdquo;, no copy-pasting.</p>
<hr>
<h2 id="memos-kt-notes-and-changelogs">Memos, KT notes, and changelogs</h2>
<p>these three are the most underrated parts of the system. they get skipped when people think about &ldquo;what does an AI need to know&rdquo; but they are exactly what the AI is missing when it gives you advice that misses context.</p>
<p><strong>Memos (<code>memo/</code>)</strong> are for anything that does not fit in a doc or a todo. decision logs, architecture choices, research, migration plans, meeting outputs. the key thing about a memo is it captures the <em>why</em>. a doc says &ldquo;the auth middleware works like this&rdquo;. a memo says &ldquo;we rewrote the auth middleware because legal flagged the session token storage in April&rdquo;. without the memo Claude treats every piece of code as a deliberate, still-valid decision. with the memo it knows what is intentional and what is technical debt inherited from a compliance scramble.</p>
<p><strong>KT notes (<code>memo/kt/&lt;platform&gt;/YYYY-MM-DD_topic.md</code>)</strong> are specifically for inheriting a codebase. when someone does a knowledge transfer session, you write it up here. when you figure out something non-obvious about how the code works, you write it up here. these are the things that would take a new person weeks to discover by reading code — undocumented conventions, &ldquo;we don&rsquo;t touch that file because&rdquo;, quirks of the build system, context behind a weird architectural choice. writing them down once means Claude knows them forever.</p>
<p><strong>Changelogs (<code>changelog/&lt;project&gt;.md</code>)</strong> are append-only per-project ship logs:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>| 2026-04-15 | Migrated inbox to VIPER          | PR #441 |
</span></span><span style="display:flex;"><span>| 2026-04-08 | Upgraded to AGP 8.3              | PR #438 |
</span></span><span style="display:flex;"><span>| 2026-03-22 | Added push notification handling | PR #421 |
</span></span></code></pre></div><p>one row per notable change. the practical use: &ldquo;did we ship X on all platforms yet?&rdquo; — you check the changelog instead of grepping git history across five repos. also useful at standup when someone asks what shipped last week.</p>
<hr>
<h2 id="the-local-web-dashboard">The local web dashboard</h2>
<p><img alt="Quick links panel — one-click access to docs, scripts, and frequently used paths across all projects." loading="lazy" src="/img/command-center-images/cce-home-quicklinks.png"></p>
<p><img alt="Keyboard shortcuts reference — configured per-project so you never forget the exact command flags." loading="lazy" src="/img/command-center-images/cce-shortcuts.png"></p>
<p>the dashboard is a local Node.js server. no framework, no build step, runs offline, starts in two seconds.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>node .ops/dashboard/server.js
</span></span><span style="display:flex;"><span><span style="color:#75715e"># opens at localhost:3000</span>
</span></span></code></pre></div><p><strong>File browser</strong> — tree sidebar over all docs, todos, memos. files render as Markdown. todo files have live checkboxes — clicking one calls <code>POST /api/toggle</code> and writes the change directly to disk.</p>
<p><strong>Git status panel</strong> — polls all repos in parallel. branch, last commit, time ago, dirty file count.</p>
<p><strong>Full-text search</strong> — index built at startup from every <code>.md</code>, <code>.txt</code>, <code>.sh</code> file. AND-matched with scoring. returns results with line-number snippets. useful when you remember something exists but can not remember which doc it is in.</p>
<p><strong>Doc staleness indicators</strong> — green/yellow/red dots next to each doc in the sidebar based on <code>doc_sync.js</code> output. a resync button re-runs the script and refreshes the cache.</p>
<p><strong>Task creation</strong> — a form on every page to add a todo at any priority level to any project. finds the right heading and inserts the item, updates the <code>Last updated:</code> stamp.</p>
<hr>
<h2 id="shape-it-to-your-problems--the-cmd-tabs-and-rss-feeds">Shape it to your problems — the CMD tabs and RSS feeds</h2>
<p>here is the thing: everyone&rsquo;s pain is different. the folder structure and scripts above are the common base. but the reason this actually works day-to-day is that you can add whatever else you actually need on top.</p>
<p>for me, the two things i added that made the biggest difference:</p>
<p><img alt="Embedded terminal with per-project tabs — each one opens a PTY in that project&rsquo;s directory. Quick-command buttons above run the commands you&rsquo;d otherwise forget." loading="lazy" src="/img/command-center-images/cce-terminal.png"></p>
<p><strong>CMD view</strong> — <code>xterm.js</code> + <code>node-pty</code> over WebSocket. a real terminal embedded in the browser, one tab per project. each tab opens a PTY session in that project&rsquo;s directory. per-project quick-command buttons — you configure a label and a shell command, they appear as buttons above the terminal. so <code>Build Debug</code> runs <code>./gradlew assembleDebug</code> in the Android tab. <code>Sync Pods</code> runs <code>pod install</code> in the iOS tab. i click once, watch it run. no switching windows, no remembering the exact command flags.</p>
<p>before this i was constantly switching terminal windows and losing track of which one was which. now everything is in one browser tab.</p>
<p><img alt="RSS feeds grouped by platform — no algorithm, no app, just the dev blogs and release channels you actually want to follow." loading="lazy" src="/img/command-center-images/cce-rss.png"></p>
<p><strong>RSS feeds / newsletters</strong> — each platform has its own dev newsletter and release channel. iOS dev forum, Android releases, Kotlin blog. i added an RSS tab. feed URLs live in a <code>feeds.json</code> file, keyed by platform:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;ios&#34;</span>: [
</span></span><span style="display:flex;"><span>    { <span style="color:#f92672">&#34;label&#34;</span>: <span style="color:#e6db74">&#34;iOS Dev Weekly&#34;</span>, <span style="color:#f92672">&#34;url&#34;</span>: <span style="color:#e6db74">&#34;https://iosdevweekly.com/issues.rss&#34;</span> },
</span></span><span style="display:flex;"><span>    { <span style="color:#f92672">&#34;label&#34;</span>: <span style="color:#e6db74">&#34;Swift Blog&#34;</span>, <span style="color:#f92672">&#34;url&#34;</span>: <span style="color:#e6db74">&#34;https://swift.org/atom.xml&#34;</span> }
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;android&#34;</span>: [
</span></span><span style="display:flex;"><span>    { <span style="color:#f92672">&#34;label&#34;</span>: <span style="color:#e6db74">&#34;Android Developers Blog&#34;</span>, <span style="color:#f92672">&#34;url&#34;</span>: <span style="color:#e6db74">&#34;https://feeds.feedburner.com/blogspot/hsDu&#34;</span> }
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>the server fetches them server-side (handles redirects, CDATA stripping), renders as cards per platform. i stop by when i want to catch up. no separate app, no subscriptions, no algorithm deciding what i see — just the feeds i actually want, inside the same tab i already have open.</p>
<p>neither of these exist in anyone else&rsquo;s command center because they are solving my specific workflow pain. the point is the base layer gives you the foundation. the top layer is yours to build.</p>
<p>other ideas i have seen or thought about that i haven&rsquo;t built yet: a meeting notes tab that auto-stamps today&rsquo;s date, a platform-specific analytics panel, a PR review queue for when you work with a team.</p>
<hr>
<h2 id="the-two-tier-ai-model">The two-tier AI model</h2>
<p><img alt="Local AI chat powered by Mistral 7B via Ollama — answers questions about your codebase from the RAG index, free and fully offline." loading="lazy" src="/img/command-center-images/cce-local-ai-chat.png"></p>
<p>the local web dashboard has a built-in AI chat powered by Mistral 7B via Ollama — not Claude. this is the layer that routes cheap questions away from the cloud.</p>
<p>the RAG pipeline:</p>
<pre tabindex="0"><code>question
   │
   ▼
embed ──► LanceDB vector search ──► top-k doc chunks
                                          │
                                          ▼
                             Mistral 7B ◄── context + question
                                          │
                                          ▼
                                    streamed answer
                               (with source file citations)
</code></pre><p>at startup the server walks all docs, chunks them, embeds them and stores the index in LanceDB. conversation history (last 12 turns) is passed with each request. topics can be filtered per platform.</p>
<p>but here is the part that matters more — the local model is also wired directly into Claude as an MCP tool. not just the dashboard chat, but Claude itself can call it:</p>
<pre tabindex="0"><code>search_docs(query, project?)  — semantic search over the LanceDB index
ask_local(question, project?) — full RAG query to Mistral 7B
</code></pre><p>so when you ask Claude &ldquo;where is the WebSocket manager?&rdquo; Claude does not think about it, does not run three tool calls, does not burn tokens. it calls <code>ask_local</code>, gets the answer back from the local model as a tool response, and continues. the routing decision is encoded in <code>CLAUDE.md</code> as explicit rules so it happens automatically:</p>
<pre tabindex="0"><code>You
 │
 ├── Complex reasoning ──────────────────► Claude (API tokens)
 │    debugging, architecture,
 │    multi-file refactoring, codegen
 │
 └── Lookups + summaries ──► local MCP ──► Mistral 7B (free, local)
      &#34;where is X?&#34;, todos,
      file summaries, templates
</code></pre><p>questions that go local: &ldquo;where is ClassName defined&rdquo;, &ldquo;what files are in folder X&rdquo;, &ldquo;summarise this file&rdquo;, &ldquo;what todos are open for Android&rdquo;, &ldquo;what is the VIPER template for a new scene&rdquo;, anything answerable by reading the existing docs.</p>
<p>questions that use Claude: multi-file refactoring, debugging across call chains, cross-platform analysis with real reasoning, writing new features.</p>
<p>in practice around 60–70% of session queries route to the local model. those run free on my machine. Claude gets the work that actually needs it.</p>
<h3 id="tracking-what-you-saved">Tracking what you saved</h3>
<p>there is one more hook worth adding: a PostToolUse hook on the local MCP calls. every time Claude calls <code>ask_local</code> or <code>search_docs</code>, a small Python script logs the call to a <code>token_savings.jsonl</code> file with a timestamp, the tool used, and an estimated token count saved:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#f92672">&#34;ts&#34;</span>: <span style="color:#e6db74">&#34;2026-04-26T10:32:11&#34;</span>, <span style="color:#f92672">&#34;tool&#34;</span>: <span style="color:#e6db74">&#34;ask_local&#34;</span>,    <span style="color:#f92672">&#34;estTokensSaved&#34;</span>: <span style="color:#ae81ff">400</span>}
</span></span><span style="display:flex;"><span>{<span style="color:#f92672">&#34;ts&#34;</span>: <span style="color:#e6db74">&#34;2026-04-26T10:33:45&#34;</span>, <span style="color:#f92672">&#34;tool&#34;</span>: <span style="color:#e6db74">&#34;search_docs&#34;</span>,  <span style="color:#f92672">&#34;estTokensSaved&#34;</span>: <span style="color:#ae81ff">250</span>}
</span></span></code></pre></div><p>the same hook also outputs a reminder back into Claude&rsquo;s context: <em>&ldquo;you just used the local model — append <code>[tib-mcp-info]</code> to the sentence in your response that came from this result.&rdquo;</em></p>
<p>that <code>[tib-mcp-info]</code> tag in the response is how you know which parts Claude answered from local knowledge vs the local model. it is easy to skip but worth keeping — after a few weeks you can look at the JSONL and get a rough sense of how many tokens the routing saved. it also keeps you honest about whether the local model is actually being used or whether Claude is quietly doing everything itself.</p>
<hr>
<h2 id="the-session-cache--picking-up-exactly-where-you-left-off">The session cache — picking up exactly where you left off</h2>
<p>the session briefing knows &ldquo;what was worked on last session&rdquo; because <code>/callitaday</code> writes a <code>session_summary.json</code> at the end of each day. the structure:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;date&#34;</span>: <span style="color:#e6db74">&#34;2026-04-22&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;platform&#34;</span>: <span style="color:#e6db74">&#34;ios&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;done&#34;</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Settings flatten complete — SettingsSUI/NewUI/Settings_base merged into Features/Settings&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Helpers restructured — Contacts moved to Features/Contacts&#34;</span>
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;carriedOver&#34;</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Android: edge to edge mandate for Play Store — not checked yet&#34;</span>
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;decisions&#34;</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Contacts gets Features/Contacts/ not buried in Helpers&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;URLSchemeAnalyser lives in Core/DeepLinker/&#34;</span>
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;openQuestions&#34;</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;CustomContextMenu still needs to move to Features/Inbox/Actions/&#34;</span>
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;keyFiles&#34;</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;native/TeamInbox.xcodeproj/project.pbxproj&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;native/TeamInbox/Features/Settings/&#34;</span>
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>next morning, <code>session_context.sh</code> reads this file and includes the <code>done</code>, <code>carriedOver</code>, <code>decisions</code>, and <code>openQuestions</code> fields in the briefing. Claude starts the session knowing exactly where things were left — no re-reading git log, no &ldquo;what were we working on?&rdquo;. the <code>keyFiles</code> field is useful if you want Claude to immediately orient to the relevant parts of the code.</p>
<p><code>/callitaday</code> is the slash command that writes this. it wraps the session: moves done items from <code>daily.md</code> back to the project todo files, carries over incomplete items, writes the JSON. it is the last thing you run before closing the terminal.</p>
<hr>
<h2 id="setting-this-up-yourself">Setting this up yourself</h2>
<p>the minimum version of this is five files and an afternoon:</p>
<ol>
<li>create a parent workspace folder above all your repos</li>
<li>add a <code>.ops/</code> folder with <code>docs/</code>, <code>todo/</code>, <code>memo/</code>, <code>scripts/</code></li>
<li>write a <code>CLAUDE.md</code> at the workspace root — folder layout, git command prefixes, working conventions, routing rules</li>
<li>write <code>session_context.sh</code> or a simple briefing script that runs <code>git -C &lt;project&gt;/ status</code> across all repos and prints a summary — hook it to session start</li>
<li>write one doc per project covering the folder structure and architecture, add the <code>watches</code> frontmatter</li>
</ol>
<p>that is the base. that alone kills the &ldquo;re-explain everything every session&rdquo; problem and the &ldquo;docs live in Notion somewhere&rdquo; problem.</p>
<p>layer on top in order of payoff:</p>
<ul>
<li><code>daily_reset.sh</code> and the <code>daily.md</code> workflow — probably adds the most to day-to-day sanity</li>
<li><code>doc_sync.js</code> — if you are writing docs and want them to stay honest</li>
<li>the dashboard — once you want a visual layer over all of it</li>
<li>the CMD tabs — if you are constantly switching terminal windows for the same commands</li>
<li>the local model + MCP — when token pressure is real and your doc library is large enough to justify a RAG pipeline</li>
</ul>
<p>do not build all of it at once. start with the folder structure and the <code>CLAUDE.md</code>. add the rest as you actually feel the pain they solve.</p>
<hr>
<h2 id="what-changed">What changed</h2>
<p>before: open the right repo in Xcode, find the right Notion page, check Slack for where i left off, re-explain the codebase to Claude, watch the first 30% of my context window fill with boilerplate before writing a single line of actual code.</p>
<p>after: one terminal, one browser tab, one Claude session. the Command Center has the state of every repo, every doc, every task, every recent decision — and the cheap questions never reach the cloud.</p>
<p>the whole system is about 1,500 lines of Node.js, a handful of shell scripts, and Markdown files. no heavy dependencies, no cloud services, runs entirely offline.</p>
<p>if you are managing more than two active repos and you are constantly re-orienting your AI every session — this pattern is worth trying. you do not have to build the whole thing. start with the folder structure and a <code>CLAUDE.md</code>. that alone will change how your sessions feel.</p>
<p>the rest you will figure out as you go, shaped around whatever is actually slowing you down. that is the point.</p>
<hr>
<p><em>a note on this post — the ideas, the frustration, the architecture, the decisions are all mine. i used Claude to help structure and articulate things i already knew but was too lazy to write out properly. felt right to mention it given the whole post is about working with AI. use your tools.</em></p>
<p><em>after writing this i came across andrej karpathy&rsquo;s wiki pattern — same instinct around plain files, single source of truth, readable by humans and machines. worth looking up if this resonated.</em></p>
]]></content:encoded></item><item><title>Visualizing Ideas with Claude: Setting Up the Official Draw.io MCP Server</title><link>https://md.eknath.dev/posts/ai-ml/drawio-mcp-server-setup/</link><pubDate>Tue, 17 Feb 2026 12:00:00 +0530</pubDate><guid>https://md.eknath.dev/posts/ai-ml/drawio-mcp-server-setup/</guid><description>&lt;h2 id="tldr---quick-setup">TL;DR - Quick Setup&lt;/h2>
&lt;p>Want to generate diagrams directly in Claude? Here is the fast track configuration for your &lt;code>claude_desktop_config.json&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;mcpServers&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;drawio&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;command&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;npx&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;args&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;-y&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;@drawio/mcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Restart Claude Desktop, and then ask: &lt;em>&amp;ldquo;Create a flowchart for a user login system.&amp;rdquo;&lt;/em>&lt;/p>
&lt;hr>
&lt;h2 id="why-drawio-with-claude">Why Draw.io with Claude?&lt;/h2>
&lt;p>If you are like me, explaining architecture or complex flows in text can get wordy and confusing. &amp;ldquo;Component A talks to B, which then signals C&amp;hellip;&amp;rdquo; is much harder to parse than a simple arrow connecting boxes.&lt;/p></description><content:encoded><![CDATA[<h2 id="tldr---quick-setup">TL;DR - Quick Setup</h2>
<p>Want to generate diagrams directly in Claude? Here is the fast track configuration for your <code>claude_desktop_config.json</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;mcpServers&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;drawio&#34;</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;command&#34;</span>: <span style="color:#e6db74">&#34;npx&#34;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;args&#34;</span>: [
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;-y&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;@drawio/mcp&#34;</span>
</span></span><span style="display:flex;"><span>      ]
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Restart Claude Desktop, and then ask: <em>&ldquo;Create a flowchart for a user login system.&rdquo;</em></p>
<hr>
<h2 id="why-drawio-with-claude">Why Draw.io with Claude?</h2>
<p>If you are like me, explaining architecture or complex flows in text can get wordy and confusing. &ldquo;Component A talks to B, which then signals C&hellip;&rdquo; is much harder to parse than a simple arrow connecting boxes.</p>
<p>The <strong>Official Draw.io MCP Server</strong> (<code>@drawio/mcp</code>) bridges this gap. It allows Claude to:</p>
<ol>
<li><strong>Generate Diagrams</strong>: Create flowcharts, sequence diagrams, and system architectures from scratch.</li>
<li><strong>Edit Existing Diagrams</strong>: Update diagrams based on new requirements.</li>
<li><strong>Render Visuals</strong>: See the diagram directly in the chat interface (depending on the client support).</li>
</ol>
<p>This is a game-changer for documentation, brainstorming, and technical specs.</p>
<hr>
<h2 id="prerequisites">Prerequisites</h2>
<p>Before we start, ensure you have the following:</p>
<ul>
<li><strong>Claude Desktop App</strong>: Installed on your Mac or Linux machine.</li>
<li><strong>Node.js</strong>: Version 18 or higher.
<ul>
<li>Check your version: <code>node -v</code></li>
<li>If missing, I recommend using <code>nvm</code> (Node Version Manager) to install it.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="step-by-step-setup-guide">Step-by-Step Setup Guide</h2>
<h3 id="1-locate-configuration-file">1. Locate Configuration File</h3>
<p>You need to edit the highly specific <code>claude_desktop_config.json</code> file.</p>
<p><strong>On macOS:</strong>
Open your terminal and run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>code ~/Library/Application<span style="color:#ae81ff">\ </span>Support/Claude/claude_desktop_config.json
</span></span></code></pre></div><p><em>(Or use <code>nano</code>, <code>vim</code>, or <code>open -e</code> if you don&rsquo;t use VS Code)</em></p>
<p><strong>On Linux:</strong>
The file is typically located at:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>~/.config/Claude/claude_desktop_config.json
</span></span></code></pre></div><h3 id="2-add-the-drawio-server">2. Add the Draw.io Server</h3>
<p>Add the following entry to the <code>mcpServers</code> object in your config file. If the file is empty, wrap it in curly braces.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;mcpServers&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;drawio&#34;</span>: {
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;command&#34;</span>: <span style="color:#e6db74">&#34;npx&#34;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;args&#34;</span>: [
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;-y&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;@drawio/mcp&#34;</span>
</span></span><span style="display:flex;"><span>      ]
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p><strong>What is this doing?</strong></p>
<ul>
<li>It tells Claude to run the <code>npx</code> command.</li>
<li>The <code>-y</code> flag automatically creates the environment without prompting.</li>
<li><code>@drawio/mcp</code> is the official package containing the server logic.</li>
</ul>
<h3 id="3-restart-claude">3. Restart Claude</h3>
<p>For the changes to take effect:</p>
<ol>
<li>Close the Claude Desktop interface completely.</li>
<li>Re-open it.</li>
</ol>
<p>You should see a generic &ldquo;MCP&rdquo; icon or indicator (depending on your version) showing that tools are loaded.</p>
<hr>
<h2 id="alternative-setup-with-claude-code-cli">Alternative: Setup with Claude Code CLI</h2>
<p>If you prefer using the <strong>Claude Code CLI</strong> (command line interface) instead of the Desktop app, you can add the server directly using the <code>claude mcp add</code> command.</p>
<p>This is particularly useful if you want to scope the tool to a specific project or your user account without editing JSON files manually.</p>
<h3 id="one-line-setup">One-Line Setup</h3>
<p>Run this command in your terminal:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>claude mcp add drawio --scope user -- npx -y @drawio/mcp
</span></span></code></pre></div><p><strong>Breakdown of the command:</strong></p>
<ul>
<li><code>claude mcp add drawio</code>: Tells Claude to add a new MCP server named &ldquo;drawio&rdquo;.</li>
<li><code>--scope user</code>: Installs it globally for your user account (use <code>--scope project</code> to install for the current folder only).</li>
<li><code>--</code>: Separator indicating the start of the actual server command.</li>
<li><code>npx -y @drawio/mcp</code>: The command to run the Draw.io server.</li>
</ul>
<p>Once added, you can verify it with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>claude mcp list
</span></span></code></pre></div><hr>
<h2 id="how-to-use-it">How to Use It</h2>
<p>Once connected, you can converse with Claude naturally about diagrams.</p>
<h3 id="creating-a-new-diagram">Creating a New Diagram</h3>
<p><strong>Prompt:</strong></p>
<blockquote>
<p>&ldquo;Create a sequence diagram for an OAuth 2.0 authentication flow involving a User, Client App, Authorization Server, and Resource Server.&rdquo;</p>
</blockquote>
<p>Claude will generate the XML or specific format required for Draw.io and often provide a link or a rendered view.</p>
<h3 id="editing-a-diagram">Editing a Diagram</h3>
<p>If you have a diagram file (e.g., XML) in your project context, you can ask Claude to modify it.</p>
<p><strong>Prompt:</strong></p>
<blockquote>
<p>&ldquo;Update the attached architecture diagram to include a Redis cache layer between the API and the Database.&rdquo;</p>
</blockquote>
<h3 id="complex-visualizations">Complex Visualizations</h3>
<p>You aren&rsquo;t limited to simple boxes. You can ask for:</p>
<ul>
<li><strong>Mind Maps</strong>: &ldquo;Create a mind map for a marketing strategy.&rdquo;</li>
<li><strong>ER Diagrams</strong>: &ldquo;Generate an Entity-Relationship diagram for an e-commerce database schema.&rdquo;</li>
<li><strong>Network Topologies</strong>: &ldquo;Draw a high-availability AWS network setup with public and private subnets.&rdquo;</li>
</ul>
<hr>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="command-not-found-npx">&ldquo;Command not found: npx&rdquo;</h3>
<p>If Claude complains it can&rsquo;t find <code>npx</code>, you might need to provide the absolute path.</p>
<ol>
<li>Run <code>which npx</code> in your terminal. (e.g., <code>/usr/local/bin/npx</code>)</li>
<li>Update your config:
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span><span style="color:#e6db74">&#34;drawio&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;command&#34;</span>: <span style="color:#e6db74">&#34;/usr/local/bin/npx&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;args&#34;</span>: [<span style="color:#e6db74">&#34;-y&#34;</span>, <span style="color:#e6db74">&#34;@drawio/mcp&#34;</span>]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div></li>
</ol>
<h3 id="server-error--disconnection">Server Error / Disconnection</h3>
<p>If the server crashes, check your Node.js version. The Draw.io MCP server requires a modern Node environment. Ensure <code>node -v</code> returns <code>v18.x.x</code> or newer.</p>
<hr>
<h2 id="resources">Resources</h2>
<ul>
<li><a href="https://github.com/jgraph/drawio-mcp">Official Draw.io MCP GitHub Repository</a></li>
<li><a href="https://modelcontextprotocol.io">Model Context Protocol Documentation</a></li>
<li><a href="https://www.draw.io">Draw.io Website</a></li>
</ul>
]]></content:encoded></item><item><title>Supercharging Claude Code with Serena - Save 70% on Tokens</title><link>https://md.eknath.dev/posts/ai-ml/serena-claude-code-setup/</link><pubDate>Wed, 04 Feb 2026 10:00:00 +0530</pubDate><guid>https://md.eknath.dev/posts/ai-ml/serena-claude-code-setup/</guid><description>&lt;h2 id="tldr---quick-setup">TL;DR - Quick Setup&lt;/h2>
&lt;p>Already know what Serena is? Here&amp;rsquo;s the fast track:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 1. Install uv and Serena&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -LsSf https://astral.sh/uv/install.sh | sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>source ~/.zshrc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>uv tool install git+https://github.com/oraios/serena
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 2. Restart terminal, then connect to your project&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd /path/to/your/project
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>claude mcp add serena -- serena-mcp-server --project &lt;span style="color:#66d9ef">$(&lt;/span>pwd&lt;span style="color:#66d9ef">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>echo &lt;span style="color:#e6db74">&amp;#34;.serena/&amp;#34;&lt;/span> &amp;gt;&amp;gt; .gitignore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 3. Start Claude&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>claude --allowedTools &lt;span style="color:#e6db74">&amp;#34;mcp__serena*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then tell Claude: &lt;em>&amp;ldquo;Use Serena to onboard this project.&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>Want to understand what this does and why? Read on.&lt;/p></description><content:encoded><![CDATA[<h2 id="tldr---quick-setup">TL;DR - Quick Setup</h2>
<p>Already know what Serena is? Here&rsquo;s the fast track:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># 1. Install uv and Serena</span>
</span></span><span style="display:flex;"><span>curl -LsSf https://astral.sh/uv/install.sh | sh
</span></span><span style="display:flex;"><span>source ~/.zshrc
</span></span><span style="display:flex;"><span>uv tool install git+https://github.com/oraios/serena
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2. Restart terminal, then connect to your project</span>
</span></span><span style="display:flex;"><span>cd /path/to/your/project
</span></span><span style="display:flex;"><span>claude mcp add serena -- serena-mcp-server --project <span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;.serena/&#34;</span> &gt;&gt; .gitignore
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3. Start Claude</span>
</span></span><span style="display:flex;"><span>claude --allowedTools <span style="color:#e6db74">&#34;mcp__serena*&#34;</span>
</span></span></code></pre></div><p>Then tell Claude: <em>&ldquo;Use Serena to onboard this project.&rdquo;</em></p>
<p>Want to understand what this does and why? Read on.</p>
<hr>
<h2 id="a-quick-note">A Quick Note</h2>
<p>This is a continuation of my <a href="https://md.eknath.dev/posts/ai-ml/claude-code-notes/">Claude Code notes</a>. If you haven&rsquo;t read that yet, I recommend starting there for the fundamentals. This article focuses on a specific optimization that has dramatically improved my Claude Code experience.</p>
<p><strong>What you&rsquo;ll learn:</strong></p>
<ul>
<li>Why Claude Code can get expensive on large codebases</li>
<li>How Serena uses LSP to provide semantic code navigation</li>
<li>Step-by-step setup (takes ~5 minutes)</li>
<li>Practical usage patterns and prompts</li>
<li>When to use Serena vs. vanilla Claude Code</li>
</ul>
<hr>
<h2 id="the-problem-token-costs-add-up-fast">The Problem: Token Costs Add Up Fast</h2>
<p>If you&rsquo;ve been using Claude Code for a while, you&rsquo;ve probably noticed that <strong>token costs can spiral quickly</strong> - especially on large codebases. Here&rsquo;s why:</p>
<p>When you ask Claude something like <em>&ldquo;Where is the authentication logic?&rdquo;</em>, it often:</p>
<ol>
<li>Reads entire files to understand context</li>
<li>Scans through multiple modules looking for patterns</li>
<li>Sometimes re-reads files it already looked at</li>
</ol>
<p>For a medium-sized project (50k+ lines of code), a single exploration session can consume <strong>thousands of tokens</strong> just reading files. Multiply that across a day&rsquo;s work, and you&rsquo;re looking at serious costs.</p>
<p>Worse, when the context window fills up, Claude can start <strong>hallucinating</strong> - referencing functions that don&rsquo;t exist or suggesting patterns that don&rsquo;t match your codebase.</p>
<hr>
<h2 id="enter-serena-semantic-code-navigation">Enter Serena: Semantic Code Navigation</h2>
<p><strong>Serena</strong> is an open-source MCP (Model Context Protocol) server that gives Claude Code <strong>semantic understanding</strong> of your codebase. Instead of reading entire files, Claude can now:</p>
<ul>
<li><strong>Jump directly to function definitions</strong></li>
<li><strong>Find all usages of a class or method</strong></li>
<li><strong>Navigate imports and dependencies</strong></li>
<li><strong>Understand type hierarchies</strong></li>
</ul>
<p>It does this by leveraging <strong>LSP (Language Server Protocol)</strong> - the same technology that powers your IDE&rsquo;s &ldquo;Go to Definition&rdquo; and &ldquo;Find All References&rdquo; features.</p>
<h3 id="the-results">The Results?</h3>
<p>In my testing on a ~100k line Android/KMP project:</p>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th>Without Serena</th>
          <th>With Serena</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Tokens for &ldquo;Find auth logic&rdquo;</td>
          <td>~15,000</td>
          <td>~4,500</td>
      </tr>
      <tr>
          <td>Context preservation</td>
          <td>Poor</td>
          <td>Excellent</td>
      </tr>
      <tr>
          <td>Navigation accuracy</td>
          <td>File-based guessing</td>
          <td>Semantic precision</td>
      </tr>
      <tr>
          <td>Estimated cost savings</td>
          <td>Baseline</td>
          <td><strong>~70%</strong></td>
      </tr>
  </tbody>
</table>
<p>That 70% isn&rsquo;t marketing fluff - it&rsquo;s real savings from not reading entire files when you only need specific symbols.</p>
<hr>
<h2 id="how-serena-works-under-the-hood">How Serena Works Under the Hood</h2>
<p>MCP servers extend Claude&rsquo;s capabilities through a standardized protocol (see <a href="#mcp-model-context-protocol">Glossary</a> if this is new to you). Serena specifically provides:</p>
<ol>
<li>
<p><strong>Code Indexing</strong>: When you connect Serena to Claude, it automatically builds an index of your codebase&rsquo;s symbols, types, and relationships.</p>
</li>
<li>
<p><strong>LSP Integration</strong>: Serena wraps language servers (for Kotlin, TypeScript, Python, etc.) to provide semantic navigation.</p>
</li>
<li>
<p><strong>Smart Querying</strong>: When Claude asks &ldquo;Where is <code>UserRepository</code>?&rdquo;, Serena returns the exact file and line number - not a file dump.</p>
</li>
<li>
<p><strong>Live Updates</strong>: The index updates as you modify code, staying in sync with your project.</p>
</li>
</ol>
<pre tabindex="0"><code>┌─────────────────┐      MCP Protocol      ┌─────────────────┐
│   Claude Code   │ ◄──────────────────────► │     Serena      │
│    (Client)     │                          │   (MCP Server)  │
└─────────────────┘                          └────────┬────────┘
                                                      │
                                                      │ LSP
                                                      ▼
                                             ┌─────────────────┐
                                             │  Language Server │
                                             │  (kotlin-ls,    │
                                             │   tsserver, etc) │
                                             └─────────────────┘
</code></pre><hr>
<h2 id="one-time-setup">One-Time Setup</h2>
<h3 id="prerequisites">Prerequisites</h3>
<ul>
<li>Claude Code CLI installed (<a href="https://md.eknath.dev/posts/ai-ml/claude-code-notes/">see my setup guide</a>)</li>
<li>A supported project (Kotlin, TypeScript, Python, Go, Rust, and more)</li>
</ul>
<h3 id="step-1-install-uv-package-manager">Step 1: Install <code>uv</code> Package Manager</h3>
<p>Serena uses <code>uv</code> for installation. If you don&rsquo;t have it:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># macOS/Linux</span>
</span></span><span style="display:flex;"><span>curl -LsSf https://astral.sh/uv/install.sh | sh
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Reload your shell</span>
</span></span><span style="display:flex;"><span>source ~/.zshrc  <span style="color:#75715e"># or ~/.bashrc</span>
</span></span></code></pre></div><p>Why <code>uv</code>? It&rsquo;s a fast Python package manager that handles Serena&rsquo;s dependencies cleanly.</p>
<h3 id="step-2-install-serena-tools">Step 2: Install Serena Tools</h3>
<p>Install the CLI tools globally:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>uv tool install git+https://github.com/oraios/serena
</span></span></code></pre></div><p>This gives you two commands:</p>
<ul>
<li><code>serena</code> - Project management CLI</li>
<li><code>serena-mcp-server</code> - The MCP server that Claude connects to</li>
</ul>
<h3 id="step-3-restart-your-terminal">Step 3: Restart Your Terminal</h3>
<blockquote>
<p><strong>Important</strong>: After installing <code>uv</code> and Serena, <strong>close all terminal windows and open a fresh one</strong>. This ensures your shell recognizes the new commands.</p>
</blockquote>
<p>I spent time debugging &ldquo;command not found&rdquo; errors only to realize a terminal restart fixed everything. Save yourself the frustration.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Close all terminals, then open a new one and verify</span>
</span></span><span style="display:flex;"><span>which serena
</span></span><span style="display:flex;"><span>which serena-mcp-server
</span></span></code></pre></div><p>Both should return valid paths. If not, try running <code>source ~/.zshrc</code> (or <code>~/.bashrc</code>).</p>
<h3 id="step-4-connect-serena-to-claude-code">Step 4: Connect Serena to Claude Code</h3>
<p>Navigate to your project root and register Serena as an MCP server:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd /path/to/your/project
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Add the server (this also initializes the project index automatically)</span>
</span></span><span style="display:flex;"><span>claude mcp add serena -- serena-mcp-server --project <span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span>
</span></span></code></pre></div><p><strong>What this does:</strong></p>
<ul>
<li>Registers Serena as an MCP server for Claude</li>
<li>Auto-initializes the project index (creates <code>.serena/</code> folder)</li>
<li>Scans your codebase for symbols, types, and relationships</li>
</ul>
<p><strong>Initial indexing time</strong> depends on project size:</p>
<table>
  <thead>
      <tr>
          <th>Project Size</th>
          <th>Approximate Time</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Small (&lt; 10k lines)</td>
          <td>10-30 seconds</td>
      </tr>
      <tr>
          <td>Medium (10k-50k lines)</td>
          <td>1-3 minutes</td>
      </tr>
      <tr>
          <td>Large (50k-200k lines)</td>
          <td>3-10 minutes</td>
      </tr>
      <tr>
          <td>Very Large (200k+ lines)</td>
          <td>10-20 minutes</td>
      </tr>
  </tbody>
</table>
<p>You can monitor progress at <code>http://localhost:24282</code> during indexing.</p>
<blockquote>
<p><strong>Important</strong>: Add <code>.serena/</code> to your <code>.gitignore</code>. This folder is local cache and shouldn&rsquo;t be committed.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;.serena/&#34;</span> &gt;&gt; .gitignore
</span></span></code></pre></div><p>Verify it&rsquo;s connected:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Check MCP server status</span>
</span></span><span style="display:flex;"><span>claude mcp list
</span></span></code></pre></div><p>You should see <code>serena</code> in the list with a green status.</p>
<hr>
<h2 id="handling-permission-prompts">Handling Permission Prompts</h2>
<p>When you start using Serena with Claude Code, you&rsquo;ll encounter <strong>multiple permission prompts</strong>. Claude asks for approval each time Serena wants to:</p>
<ul>
<li>Read files</li>
<li>Navigate to definitions</li>
<li>Search for symbols</li>
<li>Access the index</li>
</ul>
<p>This is good for security, but can get tedious during intensive coding sessions.</p>
<h3 id="option-1-approve-permissions-individually-recommended-for-learning">Option 1: Approve Permissions Individually (Recommended for Learning)</h3>
<p>When starting out, approve each permission manually. This helps you understand what Serena is doing and builds trust in the tool.</p>
<h3 id="option-2-auto-accept-permissions-for-serena">Option 2: Auto-Accept Permissions for Serena</h3>
<p>If you trust Serena and want a smoother experience, you can configure Claude to auto-accept its tool calls:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Start Claude with auto-accept for the current session</span>
</span></span><span style="display:flex;"><span>claude --allowedTools <span style="color:#e6db74">&#34;mcp__serena*&#34;</span>
</span></span></code></pre></div><p>This allows all Serena MCP tools without prompting, while still prompting for other potentially dangerous operations.</p>
<h3 id="option-3-dangerously-skip-all-permissions-use-with-caution">Option 3: Dangerously Skip All Permissions (Use with Caution)</h3>
<p>For experienced users who understand the risks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Skip ALL permission prompts (not just Serena)</span>
</span></span><span style="display:flex;"><span>claude --dangerously-skip-permissions
</span></span></code></pre></div><blockquote>
<p><strong>Warning</strong>: This flag bypasses ALL safety prompts - file writes, shell commands, everything. Only use this if:</p>
<ul>
<li>You&rsquo;re on a development machine (not production)</li>
<li>You understand Claude can modify/delete files without asking</li>
<li>You&rsquo;re working in a git-tracked project (easy to revert mistakes)</li>
<li>You trust your judgment to review changes before committing</li>
</ul>
</blockquote>
<p>For most users, Option 2 (<code>--allowedTools &quot;mcp__serena*&quot;</code>) is the sweet spot - smooth Serena experience while keeping other safeguards in place.</p>
<hr>
<h2 id="using-serena-with-claude-code">Using Serena with Claude Code</h2>
<h3 id="starting-a-session">Starting a Session</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Navigate to your project</span>
</span></span><span style="display:flex;"><span>cd /path/to/your/project
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Start Claude with Serena connected</span>
</span></span><span style="display:flex;"><span>claude
</span></span></code></pre></div><h3 id="onboarding-claude-to-your-project">Onboarding Claude to Your Project</h3>
<p>The first time you use Serena on a project, run this prompt:</p>
<pre tabindex="0"><code>Use Serena to onboard this project. Understand the architecture,
main modules, and key entry points.
</code></pre><p>Claude will use Serena&rsquo;s semantic capabilities to build a mental model of your codebase - without reading every file.</p>
<h3 id="practical-examples">Practical Examples</h3>
<p><strong>Finding specific implementations:</strong></p>
<pre tabindex="0"><code>Where is the UserRepository interface implemented?
</code></pre><p>Without Serena: Claude reads multiple files guessing where implementations might be.
With Serena: Claude jumps directly to the concrete class.</p>
<p><strong>Understanding call hierarchies:</strong></p>
<pre tabindex="0"><code>What functions call the `syncUserData()` method?
</code></pre><p>Serena traces all callers semantically, giving Claude precise context.</p>
<p><strong>Navigating multi-module projects:</strong></p>
<pre tabindex="0"><code>How does the :feature:auth module communicate with :core:network?
</code></pre><p>Serena understands module boundaries and can trace cross-module dependencies.</p>
<hr>
<h2 id="monitoring-and-debugging">Monitoring and Debugging</h2>
<h3 id="live-dashboard">Live Dashboard</h3>
<p>Serena provides a local web dashboard for monitoring and debugging:</p>
<pre tabindex="0"><code>http://localhost:24282
</code></pre><p>Open this URL in your browser while Serena is running. You&rsquo;ll see:</p>
<p><strong>Index Status Panel</strong></p>
<ul>
<li>Total symbols indexed (classes, functions, variables)</li>
<li>Indexing progress percentage</li>
<li>Last index update timestamp</li>
<li>Any indexing errors or warnings</li>
</ul>
<p><strong>Query Logs</strong></p>
<ul>
<li>Real-time log of Claude&rsquo;s queries to Serena</li>
<li>Which symbols were requested</li>
<li>Response times for each query</li>
<li>Helps you understand what Claude is &ldquo;thinking&rdquo;</li>
</ul>
<p><strong>Language Server Status</strong></p>
<ul>
<li>Connected language servers (kotlin-ls, tsserver, etc.)</li>
<li>Server health and memory usage</li>
<li>Restart buttons if a server becomes unresponsive</li>
</ul>
<p><strong>Cache Statistics</strong></p>
<ul>
<li>Hit/miss ratios</li>
<li>Memory usage</li>
<li>Option to clear cache if things get stale</li>
</ul>
<blockquote>
<p><strong>Tip</strong>: Keep the dashboard open in a browser tab during intensive coding sessions. If Claude seems confused or slow, check the dashboard - you might spot a language server that crashed or an indexing error.</p>
</blockquote>
<h3 id="serena-tools-available-to-claude">Serena Tools Available to Claude</h3>
<p>When connected, Claude gains access to these MCP tools (you can see these with <code>claude mcp list</code>):</p>
<table>
  <thead>
      <tr>
          <th>Tool</th>
          <th>Purpose</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>serena_get_definition</code></td>
          <td>Jump to where a symbol is defined</td>
      </tr>
      <tr>
          <td><code>serena_get_references</code></td>
          <td>Find all usages of a symbol</td>
      </tr>
      <tr>
          <td><code>serena_get_symbols</code></td>
          <td>List all symbols in a file</td>
      </tr>
      <tr>
          <td><code>serena_search_symbols</code></td>
          <td>Search for symbols by name pattern</td>
      </tr>
      <tr>
          <td><code>serena_get_hover</code></td>
          <td>Get type info and documentation</td>
      </tr>
      <tr>
          <td><code>serena_get_diagnostics</code></td>
          <td>Get compiler errors/warnings</td>
      </tr>
  </tbody>
</table>
<p>Claude automatically chooses the right tool based on your question.</p>
<h3 id="troubleshooting-common-issues">Troubleshooting Common Issues</h3>
<p><strong>&ldquo;command not found: serena&rdquo; after installation:</strong></p>
<p>This is the most common issue. Your terminal doesn&rsquo;t know about the new commands yet.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Option 1: Reload shell config</span>
</span></span><span style="display:flex;"><span>source ~/.zshrc  <span style="color:#75715e"># or ~/.bashrc</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Option 2 (recommended): Close ALL terminal windows and open a fresh one</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># This ensures a clean shell environment</span>
</span></span></code></pre></div><p><strong>&ldquo;1 MCP server failed&rdquo; error:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Remove and re-add the server</span>
</span></span><span style="display:flex;"><span>claude mcp remove serena
</span></span><span style="display:flex;"><span>claude mcp add serena -- serena-mcp-server --project <span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span>
</span></span></code></pre></div><p><strong>Index out of sync:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Rebuild the index</span>
</span></span><span style="display:flex;"><span>serena project update --name &lt;your-project-name&gt;
</span></span></code></pre></div><p><strong>Server not starting:</strong></p>
<p>Make sure you&rsquo;re in the correct project root where you ran the <code>claude mcp add</code> command.</p>
<p><strong>Language not supported:</strong></p>
<p>Check <a href="https://github.com/oraios/serena#supported-languages">Serena&rsquo;s supported languages</a>. For Android/KMP projects, Kotlin support works out of the box.</p>
<hr>
<h2 id="tip-simplify-with-aliases">Tip: Simplify with Aliases</h2>
<p>These Serena commands are verbose. If you find yourself typing them often, consider setting up shell aliases or using a tool like <a href="https://github.com/Eganathan/aliasly">Aliasly</a> to manage shortcuts across projects.</p>
<hr>
<h2 id="best-practices">Best Practices</h2>
<h3 id="1-keep-your-index-updated">1. Keep Your Index Updated</h3>
<p>After major refactors or pulling new changes:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>serena project update --name &lt;your-project-name&gt;
</span></span></code></pre></div><h3 id="2-use-specific-queries">2. Use Specific Queries</h3>
<p>Instead of:</p>
<pre tabindex="0"><code>How does authentication work?
</code></pre><p>Try:</p>
<pre tabindex="0"><code>Show me the AuthViewModel and its dependencies using Serena.
</code></pre><p>The more specific your query, the better Serena can target the exact symbols.</p>
<h3 id="3-combine-with-claudemd">3. Combine with CLAUDE.md</h3>
<p>Your <code>CLAUDE.md</code> file complements Serena perfectly. Use CLAUDE.md for:</p>
<ul>
<li>Project conventions and coding standards</li>
<li>Build commands and configuration</li>
<li>Architecture overview</li>
</ul>
<p>Use Serena for:</p>
<ul>
<li>Navigating actual code</li>
<li>Finding implementations</li>
<li>Tracing dependencies</li>
</ul>
<h3 id="4-monitor-your-savings">4. Monitor Your Savings</h3>
<p>Use <code>/cost</code> in Claude Code to track your token usage. Compare sessions before and after Serena to see the actual savings.</p>
<hr>
<h2 id="comparison-claude-code-vs-claude-code--serena">Comparison: Claude Code vs. Claude Code + Serena</h2>
<table>
  <thead>
      <tr>
          <th>Feature</th>
          <th>Without Serena</th>
          <th>With Serena</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Search Method</strong></td>
          <td>Text-based / Full file reads</td>
          <td>Symbolic / LSP-powered</td>
      </tr>
      <tr>
          <td><strong>Code Retrieval</strong></td>
          <td>Reads entire files</td>
          <td>Extracts specific symbols/blocks</td>
      </tr>
      <tr>
          <td><strong>Token Usage</strong></td>
          <td>High (linear to file size)</td>
          <td>Low (targeted retrieval)</td>
      </tr>
      <tr>
          <td><strong>Memory</strong></td>
          <td>Session-based only</td>
          <td>Persistent project indexing</td>
      </tr>
      <tr>
          <td><strong>Navigation</strong></td>
          <td>File path guessing</td>
          <td>Precise &ldquo;Go to Definition&rdquo;</td>
      </tr>
      <tr>
          <td><strong>Cross-references</strong></td>
          <td>Manual grep patterns</td>
          <td>Semantic &ldquo;Find All References&rdquo;</td>
      </tr>
      <tr>
          <td><strong>Type Understanding</strong></td>
          <td>Inferred from context</td>
          <td>Actual type hierarchy from LSP</td>
      </tr>
      <tr>
          <td><strong>Multi-module Support</strong></td>
          <td>Reads each module separately</td>
          <td>Understands module relationships</td>
      </tr>
      <tr>
          <td><strong>Context Preservation</strong></td>
          <td>Fills up quickly</td>
          <td>Stays efficient longer</td>
      </tr>
      <tr>
          <td><strong>Setup Required</strong></td>
          <td>None</td>
          <td>One-time (~5 min)</td>
      </tr>
      <tr>
          <td><strong>Token Efficiency</strong></td>
          <td>Baseline</td>
          <td><strong>~70% reduction</strong></td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="supported-languages">Supported Languages</h2>
<p>Serena works with any language that has LSP support. Here&rsquo;s the current status:</p>
<table>
  <thead>
      <tr>
          <th>Language</th>
          <th>Support Level</th>
          <th>Language Server</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Kotlin</strong></td>
          <td>Excellent</td>
          <td>kotlin-language-server</td>
      </tr>
      <tr>
          <td><strong>TypeScript/JavaScript</strong></td>
          <td>Excellent</td>
          <td>tsserver</td>
      </tr>
      <tr>
          <td><strong>Python</strong></td>
          <td>Excellent</td>
          <td>pylsp / pyright</td>
      </tr>
      <tr>
          <td><strong>Go</strong></td>
          <td>Excellent</td>
          <td>gopls</td>
      </tr>
      <tr>
          <td><strong>Rust</strong></td>
          <td>Excellent</td>
          <td>rust-analyzer</td>
      </tr>
      <tr>
          <td><strong>Java</strong></td>
          <td>Good</td>
          <td>eclipse.jdt.ls</td>
      </tr>
      <tr>
          <td><strong>C/C++</strong></td>
          <td>Good</td>
          <td>clangd</td>
      </tr>
      <tr>
          <td><strong>Swift</strong></td>
          <td>Experimental</td>
          <td>sourcekit-lsp</td>
      </tr>
  </tbody>
</table>
<p>For <strong>Android/KMP projects</strong>, Kotlin support is what matters most - and it works great.</p>
<blockquote>
<p><strong>Note</strong>: Serena auto-detects your project&rsquo;s languages and starts the appropriate language servers. You don&rsquo;t need to configure this manually.</p>
</blockquote>
<hr>
<h2 id="updating-and-managing-serena">Updating and Managing Serena</h2>
<h3 id="update-serena-to-latest-version">Update Serena to Latest Version</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>uv tool upgrade serena
</span></span></code></pre></div><h3 id="rebuild-project-index">Rebuild Project Index</h3>
<p>After major refactors, dependency updates, or pulling large changes:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>serena project update --name &lt;your-project-name&gt;
</span></span></code></pre></div><h3 id="remove-serena-from-a-project">Remove Serena from a Project</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Remove MCP server from Claude</span>
</span></span><span style="display:flex;"><span>claude mcp remove serena
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Delete the local index (optional)</span>
</span></span><span style="display:flex;"><span>rm -rf .serena/
</span></span></code></pre></div><h3 id="working-with-multiple-projects">Working with Multiple Projects</h3>
<p>Serena indexes are project-specific. To switch between projects:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Project A</span>
</span></span><span style="display:flex;"><span>cd /path/to/project-a
</span></span><span style="display:flex;"><span>claude mcp add serena -- serena-mcp-server --project <span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Project B (in a different terminal/session)</span>
</span></span><span style="display:flex;"><span>cd /path/to/project-b
</span></span><span style="display:flex;"><span>claude mcp add serena -- serena-mcp-server --project <span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span>
</span></span></code></pre></div><p>Each project maintains its own <code>.serena/</code> index.</p>
<hr>
<h2 id="when-not-to-use-serena">When NOT to Use Serena</h2>
<p>Serena isn&rsquo;t always the best choice:</p>
<ul>
<li><strong>Small scripts or single-file projects</strong>: The overhead of indexing doesn&rsquo;t pay off</li>
<li><strong>Heavily dynamic languages</strong>: LSP works best with typed languages</li>
<li><strong>Quick one-off questions</strong>: Sometimes just asking Claude directly is faster</li>
<li><strong>Non-code tasks</strong>: Documentation, git operations, etc. don&rsquo;t benefit from Serena</li>
</ul>
<p>Use judgment - Serena is a tool for <strong>navigating complex codebases</strong>, not a universal solution.</p>
<hr>
<h2 id="integration-with-my-workflow">Integration with My Workflow</h2>
<p>Here&rsquo;s how Serena fits into my daily Claude Code usage:</p>
<ol>
<li>
<p><strong>Morning context building</strong>: &ldquo;Use Serena to show me what I worked on yesterday in the :feature:dashboard module&rdquo;</p>
</li>
<li>
<p><strong>Feature development</strong>: &ldquo;Using Serena, find all places where we handle network errors and show me the patterns&rdquo;</p>
</li>
<li>
<p><strong>Code review</strong>: &ldquo;Navigate to the UserService implementation and review it for potential issues&rdquo;</p>
</li>
<li>
<p><strong>Debugging</strong>: &ldquo;Trace all callers of <code>processPayment()</code> and identify where the null check might be failing&rdquo;</p>
</li>
<li>
<p><strong>Onboarding teammates</strong>: &ldquo;Use Serena to explain the data flow from API response to UI state&rdquo;</p>
</li>
</ol>
<hr>
<h2 id="cost-analysis">Cost Analysis</h2>
<p>Let&rsquo;s break down the real savings. With Claude Sonnet at ~$3/1M input tokens:</p>
<table>
  <thead>
      <tr>
          <th>Session Type</th>
          <th>Without Serena</th>
          <th>With Serena</th>
          <th>Savings</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Quick exploration</td>
          <td>10k tokens</td>
          <td>3k tokens</td>
          <td>$0.02</td>
      </tr>
      <tr>
          <td>Feature implementation</td>
          <td>50k tokens</td>
          <td>15k tokens</td>
          <td>$0.10</td>
      </tr>
      <tr>
          <td>Full-day coding</td>
          <td>200k tokens</td>
          <td>60k tokens</td>
          <td>$0.42</td>
      </tr>
      <tr>
          <td>Monthly usage (20 days)</td>
          <td>4M tokens</td>
          <td>1.2M tokens</td>
          <td><strong>$8.40</strong></td>
      </tr>
  </tbody>
</table>
<p>These are conservative estimates. For larger codebases or Opus usage, savings multiply significantly.</p>
<hr>
<h2 id="setup-checklist">Setup Checklist</h2>
<p>Quick reference for new projects:</p>
<ul>
<li><input disabled="" type="checkbox"> Install <code>uv</code>: <code>curl -LsSf https://astral.sh/uv/install.sh | sh</code></li>
<li><input disabled="" type="checkbox"> Install Serena: <code>uv tool install git+https://github.com/oraios/serena</code></li>
<li><input disabled="" type="checkbox"> <strong>Restart terminal</strong> (close all windows, open fresh)</li>
<li><input disabled="" type="checkbox"> Verify install: <code>which serena &amp;&amp; which serena-mcp-server</code></li>
<li><input disabled="" type="checkbox"> Connect to Claude (auto-creates index): <code>claude mcp add serena -- serena-mcp-server --project $(pwd)</code></li>
<li><input disabled="" type="checkbox"> Add to .gitignore: <code>echo &quot;.serena/&quot; &gt;&gt; .gitignore</code></li>
<li><input disabled="" type="checkbox"> Test connection: <code>claude mcp list</code></li>
<li><input disabled="" type="checkbox"> Start Claude: <code>claude</code> (or <code>claude --allowedTools &quot;mcp__serena*&quot;</code> to auto-accept Serena permissions)</li>
<li><input disabled="" type="checkbox"> Onboard Claude: &ldquo;Use Serena to onboard this project&rdquo;</li>
</ul>
<hr>
<h2 id="resources">Resources</h2>
<ul>
<li><a href="https://github.com/oraios/serena">Serena GitHub Repository</a></li>
<li><a href="https://modelcontextprotocol.io/">Model Context Protocol Documentation</a></li>
<li><a href="https://md.eknath.dev/posts/ai-ml/claude-code-notes/">My Claude Code Notes</a></li>
<li><a href="https://microsoft.github.io/language-server-protocol/">LSP Specification</a></li>
</ul>
<hr>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>Serena has become an essential part of my Claude Code setup. The token savings are nice, but the real value is <strong>better context preservation</strong>. Claude makes fewer mistakes when it has precise semantic information instead of guessing from partial file reads.</p>
<p>If you&rsquo;re working on any non-trivial codebase - especially multi-module Android/KMP projects - give Serena a try. The 10-minute setup pays for itself within the first session.</p>
<p>As always, remember: <strong>AI is a copilot, not a pilot</strong>. Serena makes the copilot more efficient, but you&rsquo;re still in control.</p>
<hr>
<p><em>This article is a living document. Last updated: February 2026</em></p>
<hr>
<h2 id="glossary">Glossary</h2>
<p>New to some of these terms? Here&rsquo;s a quick reference:</p>
<h3 id="mcp-model-context-protocol">MCP (Model Context Protocol)</h3>
<p><strong>Model Context Protocol</strong> is an open standard created by Anthropic that allows AI assistants (like Claude) to connect to external tools and data sources. Think of it as a &ldquo;USB port&rdquo; for AI - any tool that implements MCP can plug into Claude and extend its capabilities.</p>
<p><strong>Example</strong>: Serena is an MCP server. When you run <code>claude mcp add serena</code>, you&rsquo;re telling Claude &ldquo;hey, there&rsquo;s a new tool you can use.&rdquo;</p>
<p><a href="https://modelcontextprotocol.io/">Learn more</a></p>
<hr>
<h3 id="lsp-language-server-protocol">LSP (Language Server Protocol)</h3>
<p><strong>Language Server Protocol</strong> is a standard created by Microsoft that powers IDE features like:</p>
<ul>
<li>&ldquo;Go to Definition&rdquo; (Ctrl/Cmd + Click)</li>
<li>&ldquo;Find All References&rdquo;</li>
<li>Auto-completion</li>
<li>Syntax errors and warnings</li>
</ul>
<p>Instead of each IDE implementing these features separately for every language, LSP provides a common interface. Your IDE talks to a &ldquo;language server&rdquo; that understands the specific language.</p>
<p><strong>Example</strong>: When you Ctrl+Click a function in VS Code and it jumps to the definition - that&rsquo;s LSP in action. Serena uses this same technology to give Claude semantic code navigation.</p>
<p><a href="https://microsoft.github.io/language-server-protocol/">Learn more</a></p>
<hr>
<h3 id="uv">uv</h3>
<p><strong>uv</strong> is a fast Python package and project manager created by <a href="https://astral.sh/">Astral</a>. It&rsquo;s like npm for Python, but significantly faster (written in Rust).</p>
<p><strong>Why Serena uses it</strong>: Serena is a Python project. <code>uv tool install</code> installs CLI tools globally, similar to <code>npm install -g</code>.</p>
<p><strong>Key commands</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Install a tool globally</span>
</span></span><span style="display:flex;"><span>uv tool install package-name
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Install from git repository</span>
</span></span><span style="display:flex;"><span>uv tool install git+https://github.com/user/repo
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Update a tool</span>
</span></span><span style="display:flex;"><span>uv tool upgrade package-name
</span></span></code></pre></div><p><a href="https://docs.astral.sh/uv/">Learn more</a></p>
<hr>
<h3 id="tokens">Tokens</h3>
<p><strong>Tokens</strong> are the fundamental units that AI models process. Roughly:</p>
<ul>
<li>1 token ≈ 4 characters in English</li>
<li>1 token ≈ 0.75 words</li>
<li>100 tokens ≈ 75 words</li>
</ul>
<p>When you send a prompt to Claude, it counts tokens. When Claude responds, it generates tokens. Both cost money with the API.</p>
<p><strong>Why this matters</strong>: If Claude reads a 1000-line file to answer a simple question, that&rsquo;s a lot of tokens wasted. Serena helps Claude read only what it needs.</p>
<hr>
<h3 id="context-window">Context Window</h3>
<p>The <strong>context window</strong> is the maximum amount of text (in tokens) that an AI model can &ldquo;remember&rdquo; during a conversation. Think of it as the AI&rsquo;s working memory.</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>Context Window</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Claude Sonnet</td>
          <td>200k tokens</td>
      </tr>
      <tr>
          <td>Claude Sonnet 4.5</td>
          <td>500k tokens</td>
      </tr>
      <tr>
          <td>GPT-4</td>
          <td>128k tokens</td>
      </tr>
  </tbody>
</table>
<p><strong>Why this matters</strong>: When the context window fills up, older information gets &ldquo;forgotten&rdquo; or summarized. With large codebases, this can cause Claude to lose track of important details. Serena&rsquo;s efficient queries help preserve context.</p>
<hr>
<h3 id="semantic-vs-syntactic">Semantic vs. Syntactic</h3>
<ul>
<li><strong>Syntactic</strong>: Understanding code as text/patterns (like grep searching for &ldquo;function&rdquo;)</li>
<li><strong>Semantic</strong>: Understanding code&rsquo;s meaning and relationships (knowing that <code>UserRepository implements Repository&lt;User&gt;</code>)</li>
</ul>
<p>Serena provides <strong>semantic</strong> navigation - it understands your code&rsquo;s structure, not just the text.</p>
<hr>
<h3 id="index--indexing">Index / Indexing</h3>
<p>When Serena &ldquo;indexes&rdquo; your project, it&rsquo;s building a searchable database of your code&rsquo;s structure:</p>
<ul>
<li>All classes, functions, and variables</li>
<li>Their locations (file + line number)</li>
<li>Their relationships (what calls what, what implements what)</li>
</ul>
<p>This is similar to how search engines index websites - they pre-process content so searches are fast.</p>
<hr>
<h3 id="cli-command-line-interface">CLI (Command Line Interface)</h3>
<p>A <strong>CLI</strong> is a text-based interface for interacting with software. Instead of clicking buttons in a GUI, you type commands.</p>
<p><strong>Examples</strong>:</p>
<ul>
<li><code>git</code> - Version control CLI</li>
<li><code>npm</code> - Node.js package manager CLI</li>
<li><code>claude</code> - Claude Code&rsquo;s CLI</li>
</ul>
<hr>
<h3 id="mcp-server-vs-client">MCP Server vs. Client</h3>
<p>In the MCP architecture:</p>
<ul>
<li><strong>Client</strong>: The AI assistant (Claude Code) that uses tools</li>
<li><strong>Server</strong>: The tool that provides capabilities (Serena, file system access, etc.)</li>
</ul>
<p>When you run <code>claude mcp add serena</code>, you&rsquo;re registering Serena as a server that Claude (the client) can connect to.</p>
<hr>
<p>Questions or feedback? Reach out:</p>
<ul>
<li><a href="mailto:mail@eknath.dev">Email</a></li>
<li><a href="https://eknath.dev">Website</a></li>
</ul>
]]></content:encoded></item><item><title>Staying Relevant with Claude Code - A Self-Note for Android &amp; KMP Developers</title><link>https://md.eknath.dev/posts/ai-ml/claude-code-notes/</link><pubDate>Fri, 09 Jan 2026 21:47:13 +0530</pubDate><guid>https://md.eknath.dev/posts/ai-ml/claude-code-notes/</guid><description>&lt;h2 id="a-quick-disclaimer">A Quick Disclaimer&lt;/h2>
&lt;p>This article is primarily a &lt;strong>self-note&lt;/strong> that I keep updating as I learn more about Claude Code. The AI tooling landscape evolves rapidly, so some information might be outdated by the time you read this. If you find something that needs updating, feel free to reach out!&lt;/p>
&lt;p>Whether you&amp;rsquo;re a &lt;strong>junior developer&lt;/strong> just getting started or a &lt;strong>senior developer&lt;/strong> looking to boost your workflow, Claude Code has something for everyone.&lt;/p></description><content:encoded><![CDATA[<h2 id="a-quick-disclaimer">A Quick Disclaimer</h2>
<p>This article is primarily a <strong>self-note</strong> that I keep updating as I learn more about Claude Code. The AI tooling landscape evolves rapidly, so some information might be outdated by the time you read this. If you find something that needs updating, feel free to reach out!</p>
<p>Whether you&rsquo;re a <strong>junior developer</strong> just getting started or a <strong>senior developer</strong> looking to boost your workflow, Claude Code has something for everyone.</p>
<hr>
<h2 id="why-should-you-care">Why Should You Care?</h2>
<p>If you&rsquo;ve read my <a href="https://md.eknath.dev/posts/software-development/devfest2025-solutionist-mindset-talk/">Solutionist Mindset talk</a>, you know I believe in <strong>using AI as a copilot, not a pilot</strong>. Claude Code embodies this philosophy perfectly—it&rsquo;s a CLI tool that sits alongside your existing workflow, helping you move faster while keeping you in control.</p>
<p>For Android and <strong>Compose Multiplatform (KMP)</strong> developers like us, having a tool that understands our codebase context is game-changing. Gradle configurations, multi-module architectures, platform-specific implementations—Claude Code can navigate all of this.</p>
<hr>
<h2 id="what-is-claude-code">What is Claude Code?</h2>
<p>Claude Code is Anthropic&rsquo;s <strong>official CLI tool</strong> that brings Claude directly into your terminal. Unlike the web interface, it:</p>
<ul>
<li><strong>Has full access to your codebase</strong> (with your permission)</li>
<li><strong>Can read, write, and edit files</strong> directly</li>
<li><strong>Runs shell commands</strong> for you</li>
<li><strong>Understands project context</strong> across multiple files</li>
<li><strong>Integrates with Git</strong> for version control operations</li>
</ul>
<p>Think of it as having a senior developer sitting next to you who can:</p>
<ul>
<li>Explore your codebase instantly</li>
<li>Write and refactor code</li>
<li>Debug issues by reading logs and stack traces</li>
<li>Create commits and PRs</li>
<li>Explain complex code sections</li>
</ul>
<hr>
<h2 id="latest-updates-january-2026">Latest Updates (January 2026)</h2>
<p><strong>Update available for Claude Code users (v: 2.1.2)!</strong></p>
<h3 id="model-selection">Model Selection</h3>
<p>Opus 4.5 is now available in model selection. While <strong>Sonnet is superior for general coding tasks</strong>, <strong>Opus is amazing for complex features and crazy bugs</strong>. You can use <code>-m</code> flag for selecting a specific model for particular task sessions.</p>
<table>
  <thead>
      <tr>
          <th>Model ID</th>
          <th>Description</th>
          <th>Context Window</th>
          <th>Relative Cost</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>claude-sonnet-4-20250514</code></td>
          <td>Sonnet 4 (default, most balanced)</td>
          <td>200K</td>
          <td>$$ (Moderate)</td>
      </tr>
      <tr>
          <td><code>claude-opus-4-20250514</code></td>
          <td>Opus 4 (most capable, slower)</td>
          <td>200K</td>
          <td>$$$$ (Very High)</td>
      </tr>
      <tr>
          <td><code>claude-sonnet-4-5-20250929</code></td>
          <td>Sonnet 4.5 (smartest, efficient)</td>
          <td>500K</td>
          <td>$$$ (High)</td>
      </tr>
      <tr>
          <td><code>claude-haiku-4-5-20251001</code></td>
          <td>Haiku 4.5 (fastest, most economical)</td>
          <td>200K</td>
          <td>$ (Low)</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p>[!WARNING]
<strong>Token Usage Warning</strong>: Continuous usage of <strong>Opus</strong> models will consume your rate limits and quota significantly faster (approx. 5-10x) than Sonnet. Use Opus only for complex debugging or architectural tasks.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Run with a specific model</span>
</span></span><span style="display:flex;"><span>claude -m claude-opus-4-20250514
</span></span></code></pre></div><h3 id="official-plugins">Official Plugins</h3>
<p>Check out the official plugins:</p>
<ul>
<li><a href="https://github.com/anthropics/claude-code/tree/main/plugins">All Plugins</a></li>
<li><a href="https://github.com/anthropics/claude-code/tree/main/plugins/code-review">Code Review Plugin</a></li>
</ul>
<hr>
<h2 id="getting-started">Getting Started</h2>
<h3 id="installation">Installation</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Using npm</span>
</span></span><span style="display:flex;"><span>npm install -g @anthropic-ai/claude-code
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Using Homebrew (macOS)</span>
</span></span><span style="display:flex;"><span>brew install claude-code
</span></span></code></pre></div><p>After installation, run <code>claude</code> in your terminal to start an interactive session. You&rsquo;ll need to authenticate with your Anthropic API key or use the <code>claude --login</code> command to login via the browser.</p>
<h3 id="basic-usage">Basic Usage</h3>
<p>Navigate to your project directory and simply run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>claude
</span></span></code></pre></div><p>This starts an interactive session where you can ask questions, request code changes, or explore your codebase.</p>
<hr>
<h2 id="essential-commands-every-developer-should-know">Essential Commands Every Developer Should Know</h2>
<h3 id="1-slash-commands">1️⃣ Slash Commands</h3>
<p>Claude Code has built-in slash commands that trigger specific workflows:</p>
<table>
  <thead>
      <tr>
          <th>Command</th>
          <th>What It Does</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>/help</code></td>
          <td>Shows available commands and usage tips</td>
      </tr>
      <tr>
          <td><code>/clear</code></td>
          <td>Clears conversation history (starts fresh)</td>
      </tr>
      <tr>
          <td><code>/compact</code></td>
          <td>Compresses the conversation to save context</td>
      </tr>
      <tr>
          <td><code>/cost</code></td>
          <td>Shows token usage and estimated costs</td>
      </tr>
      <tr>
          <td><code>/doctor</code></td>
          <td>Diagnoses installation and configuration issues</td>
      </tr>
      <tr>
          <td><code>/init</code></td>
          <td>Creates a CLAUDE.md file with project context</td>
      </tr>
      <tr>
          <td><code>/review</code></td>
          <td>Triggers code review for recent changes</td>
      </tr>
      <tr>
          <td><code>/commit</code></td>
          <td>Creates a git commit with meaningful message</td>
      </tr>
  </tbody>
</table>
<h3 id="2-the-claudemd-file">2️⃣ The CLAUDE.md File</h3>
<p>One of the most powerful features for <strong>multi-module Android/KMP projects</strong> is the <code>CLAUDE.md</code> file. Create this at your project root:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span># Project: MyKMPApp
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Architecture
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> Multi-module KMP project
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Shared module: commonMain, androidMain, iosMain
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Android app module with Jetpack Compose UI
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> iOS app using SwiftUI
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Key Conventions
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> Use Koin for dependency injection
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Room for local database (Android), SQLDelight for shared
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Ktor for networking
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> Kotlin Coroutines + Flow for async operations
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Build Commands
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`./gradlew assembleDebug`</span> - Build Android debug
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`./gradlew :shared:build`</span> - Build shared module only
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`./gradlew connectedAndroidTest`</span> - Run instrumented tests
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Module Structure
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> :app - Android application entry point
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> :shared - KMP shared code
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> :feature:home - Home feature module
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> :feature:settings - Settings feature module
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> :core:network - Networking utilities
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> :core:database - Database layer
</span></span></code></pre></div><p>Claude reads this file and uses it as <strong>persistent context</strong> for every conversation. This is incredibly useful for:</p>
<ul>
<li><strong>Multi-module navigation</strong> - Claude knows your module structure</li>
<li><strong>Consistent coding patterns</strong> - Follows your conventions</li>
<li><strong>Faster builds</strong> - Knows the right Gradle commands</li>
</ul>
<h3 id="3-vim-style-keybindings">3️⃣ Vim-Style Keybindings</h3>
<p>For terminal enthusiasts, Claude Code supports vim keybindings:</p>
<table>
  <thead>
      <tr>
          <th>Key</th>
          <th>Action</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>Escape</code></td>
          <td>Enter command mode</td>
      </tr>
      <tr>
          <td><code>i</code></td>
          <td>Return to insert mode</td>
      </tr>
      <tr>
          <td><code>Ctrl+C</code></td>
          <td>Cancel current operation</td>
      </tr>
      <tr>
          <td><code>Ctrl+D</code></td>
          <td>Exit Claude Code</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="practical-use-cases-for-androidkmp-developers">Practical Use Cases for Android/KMP Developers</h2>
<h3 id="use-case-1-exploring-unfamiliar-codebases">Use Case 1: Exploring Unfamiliar Codebases</h3>
<p>When you join a new project or inherit legacy code:</p>
<pre tabindex="0"><code>You: How is the authentication flow implemented in this app?
     Show me the key files involved.
</code></pre><p>Claude will search through your codebase, identify relevant files (ViewModels, Repositories, API services), and explain the flow.</p>
<h3 id="use-case-2-writing-compose-ui-components">Use Case 2: Writing Compose UI Components</h3>
<pre tabindex="0"><code>You: Create a bottom sheet component for filtering products.
     It should have checkboxes for categories and a price range slider.
     Follow our existing design system in :core:designsystem module.
</code></pre><p>Claude will:</p>
<ol>
<li>Look at your existing design system</li>
<li>Match the patterns and naming conventions</li>
<li>Create the component following your architecture</li>
</ol>
<h3 id="use-case-3-debugging-build-issues">Use Case 3: Debugging Build Issues</h3>
<pre tabindex="0"><code>You: I&#39;m getting this Gradle error when building the shared module:
     [paste error here]

     Help me understand and fix it.
</code></pre><p>Claude can read your <code>build.gradle.kts</code> files, understand the dependency graph, and suggest fixes.</p>
<h3 id="use-case-4-writing-platform-specific-implementations">Use Case 4: Writing Platform-Specific Implementations</h3>
<pre tabindex="0"><code>You: I need to implement biometric authentication.
     Create the expect/actual declarations for Android and iOS
     in the :core:auth module.
</code></pre><p>Claude understands KMP&rsquo;s expect/actual mechanism and generates appropriate platform-specific code.</p>
<h3 id="use-case-5-creating-git-commits">Use Case 5: Creating Git Commits</h3>
<pre tabindex="0"><code>You: /commit
</code></pre><p>Claude will:</p>
<ol>
<li>Analyze your staged changes</li>
<li>Understand the context of modifications</li>
<li>Generate a meaningful commit message</li>
<li>Create the commit</li>
</ol>
<h3 id="use-case-6-room-database-migrations">Use Case 6: Room Database Migrations</h3>
<pre tabindex="0"><code>You: I need to add a &#39;lastSyncedAt&#39; column to the UserEntity.
     Create the migration and update the entity.
</code></pre><p>Claude handles the boilerplate of Room migrations, which can be error-prone manually.</p>
<hr>
<h2 id="best-practices-for-effective-usage">Best Practices for Effective Usage</h2>
<h3 id="-do">✅ DO</h3>
<ol>
<li>
<p><strong>Be specific with context</strong> - Instead of &ldquo;fix this bug&rdquo;, say &ldquo;fix the crash in <code>UserRepository.kt</code> when the token expires&rdquo; make sure you add the file and line-number of the function or scope.</p>
</li>
<li>
<p><strong>Review generated code</strong> - Always understand what Claude writes. Don&rsquo;t blindly accept suggestions.</p>
</li>
<li>
<p><strong>Use it for exploration</strong> - Ask Claude to explain complex parts of your codebase or third-party libraries</p>
</li>
<li>
<p><strong>Leverage for boilerplate</strong> - Let Claude handle repetitive tasks like:</p>
<ul>
<li>Creating data classes from API responses</li>
<li>Writing Room entities and DAOs</li>
<li>Setting up Hilt/Koin modules</li>
<li>Creating navigation graphs</li>
<li>Writing unit test boilerplate</li>
</ul>
</li>
<li>
<p><strong>Maintain your CLAUDE.md</strong> - Keep it updated as your project evolves</p>
</li>
<li>
<p><strong>Use the right model for the task</strong> - Haiku for quick questions, Sonnet for general coding, Opus for complex debugging</p>
</li>
</ol>
<h3 id="-dont">❌ DON&rsquo;T</h3>
<ol>
<li>
<p><strong>Don&rsquo;t share sensitive data</strong> - Avoid passing API keys, secrets, or user data through Claude</p>
</li>
<li>
<p><strong>Don&rsquo;t skip the review</strong> - Especially for security-critical code (authentication, payment processing, encryption etc)</p>
</li>
<li>
<p><strong>Don&rsquo;t use it as a crutch</strong> - You should still understand the fundamentals. AI is a multiplier, not a replacement.</p>
</li>
<li>
<p><strong>Don&rsquo;t expect perfection</strong> - Claude can make mistakes. Treat its output as a starting point.</p>
</li>
<li>
<p><strong>Don&rsquo;t ignore Gradle sync</strong> - After Claude modifies <code>build.gradle.kts</code>, sync manually in Android Studio</p>
</li>
</ol>
<hr>
<h2 id="cost-management-tips">Cost Management Tips</h2>
<p>Claude Code uses API tokens, which cost money. Here&rsquo;s how to optimize:</p>
<h3 id="1-choose-the-right-model">1️⃣ Choose the Right Model</h3>
<table>
  <thead>
      <tr>
          <th>Task Type</th>
          <th>Recommended Model</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Quick questions, simple edits</td>
          <td>Haiku 4.5</td>
      </tr>
      <tr>
          <td>General development</td>
          <td>Sonnet 4/4.5</td>
      </tr>
      <tr>
          <td>Complex debugging, architecture</td>
          <td>Opus 4/4.5</td>
      </tr>
  </tbody>
</table>
<h3 id="2-use-compact-regularly">2️⃣ Use <code>/compact</code> Regularly</h3>
<p>Long conversations consume more tokens. Use <code>/compact</code> to summarize and reduce context.</p>
<h3 id="3-start-fresh-for-new-tasks">3️⃣ Start Fresh for New Tasks</h3>
<p>Use <code>/clear</code> when switching to unrelated tasks. No need to carry previous context.</p>
<h3 id="4-be-concise">4️⃣ Be Concise</h3>
<p>Instead of:</p>
<pre tabindex="0"><code>&#34;Hey Claude, I was wondering if you could maybe help me
understand how the user authentication works in this app,
like when someone logs in, what happens step by step?&#34;
</code></pre><p>Try:</p>
<pre tabindex="0"><code>&#34;Explain the login flow. Start from LoginViewModel.&#34;
</code></pre><h3 id="6-offload-tasks-to-other-modelstools-save-those-tokens">6️⃣ Offload Tasks to Other Models/Tools (Save those Tokens!)</h3>
<p>Not everything requires Claude Code&rsquo;s deep context awareness. Save your tokens by routing tasks to the right tool:</p>
<ul>
<li><strong>Use Gemini for Quick Concepts</strong>: Need to understand &ldquo;How <code>LruCache</code> works internally&rdquo; or &ldquo;Explain the Builder pattern&rdquo;? Use <strong>Gemini</strong>. It&rsquo;s fast, free/cheap, and great for general knowledge that doesn&rsquo;t need your private codebase context.</li>
<li><strong>Use ChatGPT for High-Level Project Questions</strong>: If you need advice on &ldquo;Best practices for modularizing a KMP project&rdquo; or architecture discussions where providing full code access isn&rsquo;t necessary, <strong>ChatGPT</strong> is a great option.</li>
<li><strong>Use CLI Tools for Quick Answers</strong>: If you&rsquo;re a terminal power user (using <code>tmux</code>, <code>dia</code>, etc.), tools like <strong>ddgr</strong> (DuckDuckGo from terminal) or <strong>Ollama</strong> (local models) are fantastic for quick lookups without leaving your flow.</li>
</ul>
<blockquote>
<p>[!TIP]
<strong>Pro Tip</strong>: Reserve Claude Code for tasks that <em>specifically</em> need to read your files, understand your project structure, or perform edits. For everything else, cheaper (or free) alternatives often work just as well!</p>
</blockquote>
<h3 id="7-check-costs-with-cost">7️⃣ Check Costs with <code>/cost</code></h3>
<p>Regularly run <code>/cost</code> to monitor your usage.</p>
<hr>
<h2 id="integration-with-development-workflow">Integration with Development Workflow</h2>
<h3 id="ide-integration">IDE Integration</h3>
<p>Claude Code works alongside your IDE, not inside it. A typical workflow:</p>
<ol>
<li><strong>Have your IDE open</strong> (Android Studio / Fleet / IntelliJ)</li>
<li><strong>Run Claude in a terminal</strong> (split screen works great)</li>
<li><strong>Ask Claude to make changes</strong></li>
<li><strong>Review changes in IDE</strong> (they appear instantly)</li>
<li><strong>Test and iterate</strong></li>
</ol>
<h3 id="git-workflow-integration">Git Workflow Integration</h3>
<p>Claude Code integrates nicely with Git:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Start a session</span>
</span></span><span style="display:flex;"><span>claude
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create meaningful commits</span>
</span></span><span style="display:flex;"><span>You: /commit
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a pull request</span>
</span></span><span style="display:flex;"><span>You: Create a PR <span style="color:#66d9ef">for</span> these changes. The target branch is develop.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Review code before pushing</span>
</span></span><span style="display:flex;"><span>You: Review the changes in the last commit <span style="color:#66d9ef">for</span> any issues.
</span></span></code></pre></div><hr>
<h2 id="common-gotchas-for-androidkmp-projects">Common Gotchas for Android/KMP Projects</h2>
<h3 id="1-gradle-sync-after-changes">1️⃣ Gradle Sync After Changes</h3>
<p>When Claude modifies <code>build.gradle.kts</code> files, you&rsquo;ll need to sync in Android Studio manually. Claude can&rsquo;t trigger this for you.</p>
<h3 id="2-resource-files">2️⃣ Resource Files</h3>
<p>Claude can create/modify XML resources (layouts, strings, drawables), but be careful with:</p>
<ul>
<li><strong>Generated resources</strong> (R class) - These regenerate on build</li>
<li><strong>Vector drawables</strong> - Complex paths might need manual tweaking</li>
</ul>
<h3 id="3-compose-preview">3️⃣ Compose Preview</h3>
<p>Claude-generated Compose components might need <code>@Preview</code> annotations added for visibility in Android Studio&rsquo;s preview pane.</p>
<h3 id="4-ios-specific-code">4️⃣ iOS-Specific Code</h3>
<p>For KMP projects, Claude can write Swift/Objective-C code for iOS implementations, but:</p>
<ul>
<li>You&rsquo;ll need Xcode to verify it compiles</li>
<li>Swift interop with Kotlin can be tricky</li>
</ul>
<h3 id="5-version-catalog">5️⃣ Version Catalog</h3>
<p>If you use <code>libs.versions.toml</code>, make sure Claude knows about it in your <code>CLAUDE.md</code>. Otherwise, it might use hardcoded versions.</p>
<hr>
<h2 id="my-personal-workflow">My Personal Workflow</h2>
<p>Here&rsquo;s how I typically use Claude Code for Android development:</p>
<ol>
<li>
<p><strong>Morning exploration</strong> - &ldquo;What did I work on yesterday? Show me recent changes.&rdquo;</p>
</li>
<li>
<p><strong>Feature development</strong> - Start with asking Claude to explore existing patterns, then implement following those patterns</p>
</li>
<li>
<p><strong>Code review helper</strong> - &ldquo;Review this ViewModel for potential memory leaks or coroutine issues&rdquo;</p>
</li>
<li>
<p><strong>Documentation</strong> - &ldquo;Generate KDoc comments for the public methods in NetworkClient.kt&rdquo;</p>
</li>
<li>
<p><strong>Refactoring</strong> - &ldquo;Migrate this callback-based API to use Kotlin Coroutines with Flow&rdquo;</p>
</li>
<li>
<p><strong>Test writing</strong> - &ldquo;Write unit tests for UserRepository using MockK&rdquo;</p>
</li>
</ol>
<hr>
<h2 id="advanced-mcp-servers">Advanced: MCP Servers</h2>
<p>Claude Code supports <strong>Model Context Protocol (MCP)</strong> servers, which extend its capabilities. For Android developers, interesting MCPs include:</p>
<ul>
<li><strong>File system access</strong> - Already built-in</li>
<li><strong>Git operations</strong> - Built-in</li>
<li><strong>Web search</strong> - For documentation lookups</li>
<li><strong>Custom tools</strong> - You can create your own MCP servers</li>
</ul>
<p>Check out the <a href="https://modelcontextprotocol.io/">MCP Documentation</a> for more details.</p>
<hr>
<h2 id="useful-one-liners">Useful One-Liners</h2>
<p>Quick commands I use frequently:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Start with a specific model for complex tasks</span>
</span></span><span style="display:flex;"><span>claude -m claude-opus-4-20250514
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Resume last conversation</span>
</span></span><span style="display:flex;"><span>claude --resume
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Check installation health</span>
</span></span><span style="display:flex;"><span>claude /doctor
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Quick code review</span>
</span></span><span style="display:flex;"><span>claude <span style="color:#e6db74">&#34;Review my staged changes for issues&#34;</span>
</span></span></code></pre></div><hr>
<h2 id="whats-next">What&rsquo;s Next?</h2>
<p>This article covers the fundamentals, but Claude Code is constantly evolving. I plan to update this note as I discover:</p>
<ul>
<li>New features and capabilities</li>
<li>Better workflows for KMP development</li>
<li>Integration patterns with CI/CD</li>
<li>Team collaboration strategies</li>
</ul>
<hr>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>Claude Code is a <strong>powerful addition to the Android/KMP developer toolkit</strong>. It&rsquo;s not about replacing your skills—it&rsquo;s about <strong>amplifying</strong> them. Use it to handle boilerplate, explore unfamiliar code, and move faster on repetitive tasks.</p>
<p>But remember: <strong>You are still the pilot</strong>. Claude is your copilot. Understand what it generates, review its suggestions, and keep learning the fundamentals.</p>
<p>The developers who thrive in the AI age won&rsquo;t be those who code the fastest—they&rsquo;ll be the ones who <strong>solve problems thoughtfully</strong> while leveraging every tool at their disposal.</p>
<hr>
<h2 id="resources">Resources</h2>
<ul>
<li><a href="https://docs.anthropic.com/claude-code">Official Claude Code Documentation</a></li>
<li><a href="https://github.com/anthropics/claude-code">Claude Code GitHub</a></li>
<li><a href="https://github.com/anthropics/claude-code/tree/main/plugins">Official Plugins</a></li>
<li><a href="https://modelcontextprotocol.io/">Model Context Protocol</a></li>
<li><a href="https://md.eknath.dev/posts/software-development/devfest2025-solutionist-mindset-talk/">My Solutionist Mindset Talk</a></li>
</ul>
<hr>
<p>Feel free to connect with me on:
📩 <strong><a href="mailto:mail@eknath.dev">Email</a></strong>
🌍 <strong><a href="https://eknath.dev">Website</a></strong></p>
<p><em>I wish to keep this article as a living document. Last updated: January 2026</em></p>
]]></content:encoded></item><item><title>Setting Up Claude Code Review Before Push</title><link>https://md.eknath.dev/posts/software-development/pre-push-code-review-with-claude/</link><pubDate>Wed, 20 Aug 2025 00:00:00 +0000</pubDate><guid>https://md.eknath.dev/posts/software-development/pre-push-code-review-with-claude/</guid><description>&lt;h1 id="setting-up-claude-code-review-before-push">Setting Up Claude Code Review Before Push&lt;/h1>
&lt;p>This guide will help you set up an automated code review system using Claude Code that runs before every git push, with the option to skip when needed.&lt;/p>
&lt;h2 id="prerequisites">Prerequisites&lt;/h2>
&lt;ul>
&lt;li>Claude Code CLI installed and configured&lt;/li>
&lt;li>Git repository with proper remote setup&lt;/li>
&lt;li>Terminal access&lt;/li>
&lt;/ul>
&lt;h2 id="step-1-create-the-pre-push-hook-script">Step 1: Create the Pre-Push Hook Script&lt;/h2>
&lt;p>Create a git hook that will run before every push:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Navigate to your project root&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd /path/to/your/project
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Create the hooks directory if it doesn&amp;#39;t exist&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mkdir -p .git/hooks
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Create the pre-push hook file&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>touch .git/hooks/pre-push
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Make it executable&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chmod +x .git/hooks/pre-push
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="step-2-generated-review-reports">Step 2: Generated Review Reports&lt;/h2>
&lt;p>Every code review automatically generates a timestamped markdown report with complete analysis:&lt;/p></description><content:encoded><![CDATA[<h1 id="setting-up-claude-code-review-before-push">Setting Up Claude Code Review Before Push</h1>
<p>This guide will help you set up an automated code review system using Claude Code that runs before every git push, with the option to skip when needed.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>Claude Code CLI installed and configured</li>
<li>Git repository with proper remote setup</li>
<li>Terminal access</li>
</ul>
<h2 id="step-1-create-the-pre-push-hook-script">Step 1: Create the Pre-Push Hook Script</h2>
<p>Create a git hook that will run before every push:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Navigate to your project root</span>
</span></span><span style="display:flex;"><span>cd /path/to/your/project
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create the hooks directory if it doesn&#39;t exist</span>
</span></span><span style="display:flex;"><span>mkdir -p .git/hooks
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create the pre-push hook file</span>
</span></span><span style="display:flex;"><span>touch .git/hooks/pre-push
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Make it executable</span>
</span></span><span style="display:flex;"><span>chmod +x .git/hooks/pre-push
</span></span></code></pre></div><h2 id="step-2-generated-review-reports">Step 2: Generated Review Reports</h2>
<p>Every code review automatically generates a timestamped markdown report with complete analysis:</p>
<h3 id="report-features">Report Features</h3>
<ul>
<li><strong>Filename</strong>: <code>claude-review-report_2025-08-20_14-30-45.md</code></li>
<li><strong>Complete History</strong>: All commits since main branch</li>
<li><strong>File Changes</strong>: List of all modified files</li>
<li><strong>Project Checks</strong>: Linting and type checking results</li>
<li><strong>Claude Analysis</strong>: Detailed security, bug, and quality review</li>
<li><strong>Action Checklist</strong>: Checkboxes for addressing issues</li>
</ul>
<h3 id="sample-report-structure">Sample Report Structure</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span># Claude Code Review Report
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="font-weight:bold">**Generated:**</span> 2025-08-20 14:30:45
</span></span><span style="display:flex;"><span><span style="font-weight:bold">**Branch:**</span> feature/new-ui
</span></span><span style="display:flex;"><span><span style="font-weight:bold">**Compared Against:**</span> origin/main  
</span></span><span style="display:flex;"><span><span style="font-weight:bold">**Review Status:**</span> ✅ Passed
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Commits Reviewed
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> feat: add new user interface
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> fix: resolve navigation bug
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> test: add unit tests for new component
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Files Changed
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> src/components/UserInterface.tsx
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> src/navigation/Router.tsx  
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> tests/UserInterface.test.tsx
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Project Checks
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">### Linting
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>✅ <span style="font-weight:bold">**Passed**</span> - No linting issues found
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">### Type Checking
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>⚠️ <span style="font-weight:bold">**Issues Found**</span> - See type checking output
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Claude Code Review Results
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>[Claude&#39;s detailed analysis here]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Quick Actions
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">### If Issues Found:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">- [ ]</span> Fix security vulnerabilities
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- [ ]</span> Resolve critical bugs
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- [ ]</span> Address performance issues
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><h2 id="step-3-write-the-pre-push-hook">Step 3: Write the Pre-Push Hook</h2>
<p>Add the following content to <code>.git/hooks/pre-push</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Colors for output</span>
</span></span><span style="display:flex;"><span>RED<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[0;31m&#39;</span>
</span></span><span style="display:flex;"><span>GREEN<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[0;32m&#39;</span>
</span></span><span style="display:flex;"><span>YELLOW<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[1;33m&#39;</span>
</span></span><span style="display:flex;"><span>NC<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;\033[0m&#39;</span> <span style="color:#75715e"># No Color</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Check if SKIP_CLAUDE_REVIEW environment variable is set</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$SKIP_CLAUDE_REVIEW<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;true&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">⚠️  Claude Code review skipped (SKIP_CLAUDE_REVIEW=true)</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Check if claude command is available</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> ! command -v claude &amp;&gt; /dev/null; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>RED<span style="color:#e6db74">}</span><span style="color:#e6db74">❌ Claude Code CLI not found. Install it first or skip with: SKIP_CLAUDE_REVIEW=true git push</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">🤖 Running Claude Code review before push...</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Get the current branch</span>
</span></span><span style="display:flex;"><span>current_branch<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>git branch --show-current<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Find the main/master branch</span>
</span></span><span style="display:flex;"><span>main_branch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> git show-ref --verify --quiet refs/heads/main; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    main_branch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;main&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elif</span> git show-ref --verify --quiet refs/heads/master; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    main_branch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;master&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elif</span> git show-ref --verify --quiet refs/remotes/origin/main; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    main_branch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;origin/main&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elif</span> git show-ref --verify --quiet refs/remotes/origin/master; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    main_branch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;origin/master&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">⚠️  Could not find main/master branch, comparing with HEAD~1</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    main_branch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;HEAD~1&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Check if there are any changes to review since main branch</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$main_branch<span style="color:#e6db74">&#34;</span> !<span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;HEAD~1&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> git diff --quiet <span style="color:#e6db74">&#34;</span>$main_branch<span style="color:#e6db74">&#34;</span>..HEAD 2&gt;/dev/null; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">✅ No changes detected since </span>$main_branch<span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elif</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$main_branch<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;HEAD~1&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> git diff --quiet HEAD~1 HEAD 2&gt;/dev/null; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">✅ No changes detected since last commit</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Show what&#39;s being reviewed</span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">📋 Reviewing changes in branch: </span>$current_branch<span style="color:#e6db74"> (since </span>$main_branch<span style="color:#e6db74">)</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$main_branch<span style="color:#e6db74">&#34;</span> !<span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;HEAD~1&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>BLUE<span style="color:#e6db74">}</span><span style="color:#e6db74">Commits to be reviewed:</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    git log --oneline <span style="color:#e6db74">&#34;</span>$main_branch<span style="color:#e6db74">&#34;</span>..HEAD
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>BLUE<span style="color:#e6db74">}</span><span style="color:#e6db74">Files changed:</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    git diff --name-only <span style="color:#e6db74">&#34;</span>$main_branch<span style="color:#e6db74">&#34;</span>..HEAD
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    git log --oneline -5
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">📝 Running automated code review...</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Run project-specific checks first</span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>BLUE<span style="color:#e6db74">}</span><span style="color:#e6db74">🔧 Running project checks...</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Linting</span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">  → Running linter...</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> npm run lint <span style="color:#f92672">||</span> yarn lint 2&gt;/dev/null; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">    ✅ Linting passed</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">    ⚠️  Linting issues found (will be reviewed by Claude)</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Type checking</span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">  → Running type check...</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> npm run typecheck <span style="color:#f92672">||</span> yarn typecheck <span style="color:#f92672">||</span> tsc --noEmit 2&gt;/dev/null; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">    ✅ Type checking passed</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">    ⚠️  Type issues found (will be reviewed by Claude)</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create a temporary file for the review prompt</span>
</span></span><span style="display:flex;"><span>review_file<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>mktemp<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>cat &gt; <span style="color:#e6db74">&#34;</span>$review_file<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&lt;&lt; &#39;EOF&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Please perform a comprehensive code review of ALL changes in this branch before I push to the remote repository.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">IMPORTANT: Review ALL commits since the main branch, not just the latest commit. 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Use &#39;git diff main..HEAD&#39; and &#39;git log main..HEAD&#39; to see all changes.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">The following commits will be pushed:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$(git log --oneline main..HEAD 2&gt;/dev/null || git log --oneline -5)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Files that have been changed:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$(git diff --name-only main..HEAD 2&gt;/dev/null || git diff --name-only HEAD~1 HEAD)
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Comprehensive review including security, bugs, performance, code quality, test coverage, and best practices. 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Please also run these project-specific commands and report any issues:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1. Linting: npm run lint || yarn lint
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2. Type checking: npm run typecheck || yarn typecheck || tsc --noEmit
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3. Tests: npm test || yarn test
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Focus areas:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">1. **Security issues** - Check for exposed secrets, SQL injection, XSS vulnerabilities
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">2. **Bug potential** - Logic errors, null pointer exceptions, edge cases  
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">3. **Code quality** - Following project conventions, proper error handling
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">4. **Performance** - Inefficient operations, memory issues
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">5. **All commits** - Review every commit since main branch, not just the latest one
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">If you find any critical issues, please list them clearly with file locations. 
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">If the code looks good to push, respond with: &#34;✅ Code review passed - safe to push&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Please review the ENTIRE diff since main branch, including all commits and file changes.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">📝 Running automated code review...</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Run Claude Code review</span>
</span></span><span style="display:flex;"><span>claude code &lt; <span style="color:#e6db74">&#34;</span>$review_file<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>review_exit_code<span style="color:#f92672">=</span>$?
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Clean up</span>
</span></span><span style="display:flex;"><span>rm <span style="color:#e6db74">&#34;</span>$review_file<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Check if Claude review was successful</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $review_exit_code -ne <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>RED<span style="color:#e6db74">}</span><span style="color:#e6db74">❌ Claude Code review failed</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">💡 To skip this review: SKIP_CLAUDE_REVIEW=true git push</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">🎉 Claude Code review completed!</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">💡 To skip future reviews: SKIP_CLAUDE_REVIEW=true git push</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Ask user if they want to proceed</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>read -p <span style="color:#e6db74">&#34;Do you want to proceed with the push? (y/N): &#34;</span> -n <span style="color:#ae81ff">1</span> -r
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $REPLY <span style="color:#f92672">=</span>~ ^<span style="color:#f92672">[</span>Yy<span style="color:#f92672">]</span>$ <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">✅ Proceeding with push...</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    echo -e <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>YELLOW<span style="color:#e6db74">}</span><span style="color:#e6db74">🛑 Push cancelled by user</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span></code></pre></div><h2 id="step-3-configure-your-project">Step 3: Configure Your Project</h2>
<p>Add these commands to your <code>CLAUDE.md</code> file (create if it doesn&rsquo;t exist):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span># Project Code Review Commands
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Lint Commands
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`npm run lint`</span> or <span style="color:#e6db74">`yarn lint`</span> - Run ESLint
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`npm run lint:fix`</span> or <span style="color:#e6db74">`yarn lint:fix`</span> - Fix linting issues
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Type Checking
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`npm run typecheck`</span> or <span style="color:#e6db74">`yarn typecheck`</span> - Run TypeScript checking
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`tsc --noEmit`</span> - Alternative TypeScript check
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Testing
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`npm test`</span> or <span style="color:#e6db74">`yarn test`</span> - Run all tests
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`npm run test:coverage`</span> - Run tests with coverage
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Build
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">-</span> <span style="color:#e6db74">`npm run build`</span> or <span style="color:#e6db74">`yarn build`</span> - Build the project
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## Pre-push Checklist
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>Before pushing code, ensure:
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">1.</span> All tests pass
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">2.</span> No linting errors
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">3.</span> No type errors
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">4.</span> Build succeeds
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">5.</span> No security vulnerabilities
</span></span></code></pre></div><h2 id="step-4-test-the-setup">Step 4: Test the Setup</h2>
<p>Test your setup with these commands:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Make a small change and commit it</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;// Test comment&#34;</span> &gt;&gt; src/test-file.js
</span></span><span style="display:flex;"><span>git add .
</span></span><span style="display:flex;"><span>git commit -m <span style="color:#e6db74">&#34;test: add test comment for hook testing&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Try to push (this should trigger Claude review)</span>
</span></span><span style="display:flex;"><span>git push origin your-branch-name
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Test skipping the review</span>
</span></span><span style="display:flex;"><span>SKIP_CLAUDE_REVIEW<span style="color:#f92672">=</span>true git push origin your-branch-name
</span></span></code></pre></div><h2 id="usage-examples">Usage Examples</h2>
<h3 id="normal-push-with-review">Normal push with review:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git push origin feature-branch
</span></span><span style="display:flex;"><span><span style="color:#75715e"># This will automatically run Claude Code review</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Generates: claude-review-report_YYYY-MM-DD_HH-MM-SS.md</span>
</span></span></code></pre></div><h3 id="skip-review-when-needed">Skip review when needed:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># For urgent hotfixes or when review isn&#39;t needed</span>
</span></span><span style="display:flex;"><span>SKIP_CLAUDE_REVIEW<span style="color:#f92672">=</span>true git push origin hotfix-branch
</span></span></code></pre></div><h3 id="set-up-permanent-skip-not-recommended">Set up permanent skip (not recommended):</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Add to your shell profile (.bashrc, .zshrc, etc.)</span>
</span></span><span style="display:flex;"><span>export SKIP_CLAUDE_REVIEW<span style="color:#f92672">=</span>true
</span></span></code></pre></div><h2 id="advanced-configuration">Advanced Configuration</h2>
<h3 id="custom-review-prompts">Custom Review Prompts</h3>
<p>Create different review prompts for different scenarios by modifying the hook:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># In your pre-push hook, you can customize based on branch</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $current_branch <span style="color:#f92672">==</span> hotfix* <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Use lighter review for hotfixes</span>
</span></span><span style="display:flex;"><span>    review_prompt<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Quick security and critical bug check only&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elif</span> <span style="color:#f92672">[[</span> $current_branch <span style="color:#f92672">==</span> feature* <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Full review for features</span>
</span></span><span style="display:flex;"><span>    review_prompt<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Comprehensive code review including performance and best practices&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span></code></pre></div><h3 id="integration-with-cicd">Integration with CI/CD</h3>
<p>You can also integrate this into your CI/CD pipeline:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#75715e"># .github/workflows/code-review.yml</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">Claude Code Review</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>: [<span style="color:#ae81ff">pull_request]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">review</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">steps</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Setup Claude Code</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">          # Install Claude Code CLI
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">          pip install claude-code</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Run Code Review</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">          claude code &#34;Please review this PR for security, bugs, and code quality issues&#34;</span>
</span></span></code></pre></div><h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="hook-not-running">Hook not running?</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Check if hook is executable</span>
</span></span><span style="display:flex;"><span>ls -la .git/hooks/pre-push
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Make it executable if needed</span>
</span></span><span style="display:flex;"><span>chmod +x .git/hooks/pre-push
</span></span></code></pre></div><h3 id="claude-code-not-found">Claude Code not found?</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Install Claude Code CLI</span>
</span></span><span style="display:flex;"><span>pip install anthropic-claude-code
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Or using npm</span>
</span></span><span style="display:flex;"><span>npm install -g @anthropic-ai/claude-code
</span></span></code></pre></div><h3 id="want-to-modify-the-hook">Want to modify the hook?</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Edit the hook file</span>
</span></span><span style="display:flex;"><span>nano .git/hooks/pre-push
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Or use your preferred editor</span>
</span></span><span style="display:flex;"><span>code .git/hooks/pre-push
</span></span></code></pre></div><h2 id="key-features">Key Features</h2>
<p>✅ <strong>Full Branch Review</strong>: Reviews ALL commits since branching from main, not just the latest commit<br>
✅ <strong>Smart Branch Detection</strong>: Automatically finds main/master/origin/main/origin/master<br>
✅ <strong>Auto Project Detection</strong>: Identifies JavaScript/TypeScript, Python, Java/Android projects automatically<br>
✅ <strong>Timestamped Reports</strong>: Generates permanent markdown reports with complete analysis<br>
✅ <strong>Comprehensive Analysis</strong>: Reviews security, performance, bugs, and code quality<br>
✅ <strong>Project-Specific Checks</strong>: Runs your lint, typecheck, and test commands<br>
✅ <strong>Action Checklists</strong>: Provides clear tasks for addressing any issues found<br>
✅ <strong>Detailed Reporting</strong>: Shows exactly which commits and files will be reviewed<br>
✅ <strong>Flexible</strong>: Can be skipped when needed for urgent pushes</p>
<h2 id="benefits">Benefits</h2>
<p>✅ <strong>Automated Quality Control</strong>: Catches issues before they reach the remote repository<br>
✅ <strong>Full Change Visibility</strong>: Reviews entire diff since branching from main<br>
✅ <strong>Permanent Documentation</strong>: Timestamped reports track all reviews and action items<br>
✅ <strong>Issue Tracking</strong>: Action checklists help systematically address problems<br>
✅ <strong>Educational</strong>: Learn best practices from Claude&rsquo;s feedback<br>
✅ <strong>Team Consistency</strong>: Ensures all team members follow the same review standards<br>
✅ <strong>Historical Record</strong>: Keep track of code quality improvements over time</p>
<h2 id="team-setup">Team Setup</h2>
<p>Share this setup with your team by:</p>
<ol>
<li>Adding the pre-push hook to your repository (in a <code>scripts/</code> folder)</li>
<li>Creating a setup script that copies it to <code>.git/hooks/</code></li>
<li>Documenting the process in your project&rsquo;s README</li>
<li>Adding the CLAUDE.md configuration to your repository</li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># scripts/setup-hooks.sh</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash</span>
</span></span><span style="display:flex;"><span>cp scripts/pre-push .git/hooks/pre-push
</span></span><span style="display:flex;"><span>chmod +x .git/hooks/pre-push
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;✅ Claude Code review hook installed!&#34;</span>
</span></span></code></pre></div><p>Now your code will be automatically reviewed by Claude before every push, helping maintain high code quality while giving you the flexibility to skip when needed!</p>
]]></content:encoded></item></channel></rss>