<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hariom Lohar</title>
    <description>The latest articles on DEV Community by Hariom Lohar (@hariomlohardev).</description>
    <link>https://dev.to/hariomlohardev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4044652%2Fa47846b2-0fe6-4967-acde-50775a3669e6.jpg</url>
      <title>DEV Community: Hariom Lohar</title>
      <link>https://dev.to/hariomlohardev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hariomlohardev"/>
    <language>en</language>
    <item>
      <title>How I Built a PageRank-Style Importance Ranker for Codebases in Python</title>
      <dc:creator>Hariom Lohar</dc:creator>
      <pubDate>Sat, 15 Aug 2026 01:34:53 +0000</pubDate>
      <link>https://dev.to/hariomlohardev/how-i-built-a-pagerank-style-importance-ranker-for-codebases-in-python-o47</link>
      <guid>https://dev.to/hariomlohardev/how-i-built-a-pagerank-style-importance-ranker-for-codebases-in-python-o47</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Where do I start in this repo?” — every dev, every &lt;code&gt;git clone&lt;/code&gt;. I built &lt;code&gt;peek&lt;/code&gt; to answer it in 5 seconds, without an API key.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; &lt;code&gt;peek&lt;/code&gt;’s &lt;code&gt;analyzer.py&lt;/code&gt; builds a file-level import graph with &lt;code&gt;ast&lt;/code&gt;, runs a 5-iteration PageRank-lite (damping 0.85) plus in-degree, entry-point, and &lt;code&gt;if __name__ == "__main__"&lt;/code&gt; bonuses, then penalizes &lt;code&gt;__init__.py&lt;/code&gt; and tiny stubs. On its own codebase it nails &lt;code&gt;peek/peek/cli.py&lt;/code&gt; as #1. Here’s exactly how — and where you can hack it.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Problem Isn’t “What Files Exist?” — It’s “What Matters?”
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;tree&lt;/code&gt; shows you 200 files. &lt;code&gt;tokei&lt;/code&gt; counts 13k LOC. Neither tells you that &lt;code&gt;peek/peek/cli.py&lt;/code&gt; is the front door, &lt;code&gt;peek/peek/scanner.py&lt;/code&gt; is the hub 12 modules depend on, and &lt;code&gt;peek/peek/__init__.py&lt;/code&gt; is just 2 lines you should ignore.&lt;/p&gt;

&lt;p&gt;I wanted &lt;code&gt;peek .&lt;/code&gt; to print:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start Here ⭐
  1  peek/peek/cli.py      11.7  entry point, main guard, hub (imported by 7)
  2  peek/peek/scanner.py   7.5  hub (imported by 12)
  3  peek/peek/themes.py    7.0  hub (imported by 7)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That “Start Here” is a &lt;strong&gt;ranking problem&lt;/strong&gt;, not a listing problem. Google solved it for the web in 1998. I stole it for code.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Intuition: Files Are Web Pages, Imports Are Links
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph LR
  A[peek/cli.py] --&amp;gt; B[peek/scanner.py]
  A --&amp;gt; C[peek/themes.py]
  B --&amp;gt; D[peek/analyzer.py]
  C --&amp;gt; B
  D --&amp;gt; B
  style B fill:#D4A27F,stroke:#333,color:#111
  style A fill:#8AB4B8,stroke:#333
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A page that many pages link to is important&lt;/strong&gt; → a file many files &lt;code&gt;import&lt;/code&gt; is a hub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A page linked from important pages is more important&lt;/strong&gt; → &lt;code&gt;scanner.py&lt;/code&gt; is imported by &lt;code&gt;analyzer.py&lt;/code&gt; (which is itself central) → double boost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;But unlike the web, code has entry points.&lt;/strong&gt; &lt;code&gt;cli.py&lt;/code&gt;, &lt;code&gt;main.py&lt;/code&gt;, &lt;code&gt;__main__.py&lt;/code&gt;, or anything with &lt;code&gt;if __name__ == "__main__":&lt;/code&gt; should float to the top even if nothing imports it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the score isn’t just graph centrality. It’s &lt;strong&gt;centrality + intent&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Building the Graph — The Hard Part Isn’t PageRank, It’s &lt;code&gt;import&lt;/code&gt; Parsing
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;analyzer.py&lt;/code&gt;’s &lt;code&gt;build_graph()&lt;/code&gt; does 4 things that look simple and break instantly on real repos:&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Normalize &lt;code&gt;src/&lt;/code&gt; Layout
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_module_name_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# src/peek/scanner.py -&amp;gt; peek.scanner
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lib&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_suffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_suffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this, &lt;code&gt;src/peek/scanner.py&lt;/code&gt; would never match &lt;code&gt;from peek.scanner import Foo&lt;/code&gt; in &lt;code&gt;src/peek/cli.py&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Extract Raw Imports with &lt;code&gt;ast&lt;/code&gt; (Not Regex)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Import&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="c1"&gt;# import os, import peek.scanner
&lt;/span&gt;    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ImportFrom&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# handles level=1 (from . import foo) and level=2 (from ..bar import baz)
&lt;/span&gt;        &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_relative_base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;abs_mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;
        &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abs_mod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;abs_mod&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# from peek.scanner import Foo -&amp;gt; peek.scanner.Foo
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why not regex? &lt;code&gt;from . import foo&lt;/code&gt; is relative to the file’s package. &lt;code&gt;_relative_base("peek.sub", 2)&lt;/code&gt; → &lt;code&gt;"peek"&lt;/code&gt; — you need the file’s logical package, not just the string.&lt;/p&gt;

&lt;p&gt;BOM, &lt;code&gt;SyntaxError&lt;/code&gt;, and 500 KB files are all swallowed: &lt;code&gt;return raw, set()&lt;/code&gt; — &lt;strong&gt;peek never crashes&lt;/strong&gt; is a feature, not a slogan.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Resolve to Local Files (Longest Prefix + Suffix Fallback)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_resolve_local_import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# exact: peek.scanner.Foo -&amp;gt; peek/peek/scanner.py
&lt;/span&gt;    &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;cand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cand&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cand&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;       &lt;span class="c1"&gt;# suffix fallback for src layout
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;peek.scanner.Foo&lt;/code&gt; → tries &lt;code&gt;peek.scanner.Foo&lt;/code&gt; → &lt;code&gt;peek.scanner&lt;/code&gt; → &lt;code&gt;peek&lt;/code&gt; → suffix &lt;code&gt;src.peek.scanner&lt;/code&gt;. Without the suffix fallback, every &lt;code&gt;src/&lt;/code&gt; repo would have an empty graph.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Filter Stdlib, Keep Your Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;is_stdlib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdlib_module_names&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stdlib_module_names&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_stdlib_fallback&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;is_stdlib&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;external&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# for the “Tech Stack” panel, not the graph
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;os&lt;/code&gt; / &lt;code&gt;sys&lt;/code&gt; / &lt;code&gt;ast&lt;/code&gt; never become nodes. Otherwise &lt;code&gt;os&lt;/code&gt; would be the #1 hub in every Python repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.5 Polyglot Hook (v3)
&lt;/h3&gt;

&lt;p&gt;Same &lt;code&gt;build_graph&lt;/code&gt; now also handles JS/TS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;JS_IMPORT_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;import\s+(?:.*?\s+from\s+)?[&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="s"&gt;]([^&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="s"&gt;]+)[&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="s"&gt;]|require\([&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="s"&gt;]([^&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="s"&gt;]+)[&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="s"&gt;]\)&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# relative ./b.js -&amp;gt; resolve to Path, try .js/.ts/.jsx/.tsx//index.js, add edge
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;tree-sitter&lt;/code&gt; hard dep — regex fallback keeps &lt;code&gt;pip install peek-code&lt;/code&gt; &amp;lt;10s.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Ranking Heuristic — 5 Signals, One Score
&lt;/h2&gt;

&lt;p&gt;The magic is in &lt;code&gt;rank_files()&lt;/code&gt;. Here’s the exact formula, line-for-line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pr_norm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;max_pr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# PageRank 0..5
&lt;/span&gt;&lt;span class="n"&gt;in_norm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_deg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c1"&gt;# in-degree 0..5
&lt;/span&gt;&lt;span class="n"&gt;entry_bonus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;entry_set&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;guard_bonus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;_has_main_guard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pr_norm&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;in_norm&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;entry_bonus&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;guard_bonus&lt;/span&gt;
&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="c1"&gt;# shallow files slightly preferred
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__init__.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;              &lt;span class="c1"&gt;# package init is never “Start Here”
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;loc_est&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;   &lt;span class="c1"&gt;# &amp;lt;10 real LOC: stub
&lt;/span&gt;&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;loc_est&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;

&lt;span class="c1"&gt;# Reasons for the table:
# entry point / main guard / hub (imported by N) / central / connects M modules
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Each Term Exists (and What Breaks Without It)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;What it catches&lt;/th&gt;
&lt;th&gt;Without it, this file wins incorrectly&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;pr_norm*5&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Transitive centrality — &lt;code&gt;scanner.py&lt;/code&gt; imported by &lt;code&gt;analyzer.py&lt;/code&gt; which is imported by &lt;code&gt;cli.py&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;utils.py&lt;/code&gt; with one direct import beats &lt;code&gt;scanner.py&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;in_norm&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Direct hub-ness — &lt;code&gt;scanner.py&lt;/code&gt; imported by 12&lt;/td&gt;
&lt;td&gt;A leaf &lt;code&gt;cli.py&lt;/code&gt; would tie with &lt;code&gt;scanner.py&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;entry_bonus 5.0&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cli.py&lt;/code&gt;, &lt;code&gt;main.py&lt;/code&gt;, &lt;code&gt;__main__.py&lt;/code&gt;, &lt;code&gt;pyproject.scripts&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;hub&lt;/code&gt; always beats &lt;code&gt;entry&lt;/code&gt; — you’d start in the utility, not the front door&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;guard_bonus 0.5&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;if __name__ == "__main__":&lt;/code&gt; &lt;strong&gt;via AST&lt;/strong&gt; (not substring!) + &lt;code&gt;def main()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;main.py&lt;/code&gt; without guard would lose to &lt;code&gt;utils.py&lt;/code&gt; by 0.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;__init__ -3.0&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;__init__.py&lt;/code&gt; is always imported but never where you start&lt;/td&gt;
&lt;td&gt;Every &lt;code&gt;__init__.py&lt;/code&gt; would be #1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;10 LOC -1.5&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stubs, re-exports, &lt;code&gt;__init__&lt;/code&gt; shims&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;peek/__init__.py&lt;/code&gt; (2 lines) would rank #10 as “central”&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;PageRank-lite itself:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_pagerank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;damping&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;dangling&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;out_deg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;out_deg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rev&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;out_deg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;dangling&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;
            &lt;span class="n"&gt;new_rank&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;damping&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;damping&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5 iterations, &lt;code&gt;damping=0.85&lt;/code&gt;, &lt;code&gt;dangling_sum / N&lt;/code&gt; spread — exactly the 1998 paper, but on 29 nodes not 30M. &lt;code&gt;N=1&lt;/code&gt; avoids div-zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  AST Guard vs Substring (A One-Line Bug That Fooled Me)
&lt;/h3&gt;

&lt;p&gt;Early &lt;code&gt;_has_main_guard&lt;/code&gt; was &lt;code&gt;if '"__main__"' in text: return True&lt;/code&gt; — every file mentioning &lt;code&gt;__main__&lt;/code&gt; in a comment got +0.5. The fix walks the AST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compare&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__name__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Constant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comparators&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FunctionDef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now only real &lt;code&gt;if __name__ == "__main__":&lt;/code&gt; and &lt;code&gt;def main():&lt;/code&gt; count.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. What It Looks Like on Its Own Codebase
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;peek &lt;span class="nt"&gt;--no-tui&lt;/span&gt;
&lt;span class="c"&gt;# 210 files • 13k LOC • 29 modules • 89 edges — 0.35s&lt;/span&gt;
&lt;span class="c"&gt;# Start Here ⭐  cli.py 11.7 (entry point, main guard, hub), scanner.py 7.5 (hub x12), themes.py 7.0 (hub x7)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cli.py&lt;/code&gt; wins because it has &lt;strong&gt;all three&lt;/strong&gt;: &lt;code&gt;pr_norm&lt;/code&gt; ~4.8 (central), &lt;code&gt;in_norm&lt;/code&gt; 5.0 (imported by 7), &lt;code&gt;entry_bonus&lt;/code&gt; 5.0, &lt;code&gt;guard_bonus&lt;/code&gt; 0.5 → &lt;strong&gt;11.7&lt;/strong&gt;. &lt;code&gt;scanner.py&lt;/code&gt; is second with &lt;code&gt;in_norm&lt;/code&gt; 5.0 but no &lt;code&gt;entry_bonus&lt;/code&gt; → 7.5. The math is boring. The result feels obvious.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Where It Still Breaks (and Where You Come In)
&lt;/h2&gt;

&lt;p&gt;I left seams on purpose — each is a &lt;code&gt;good first issue&lt;/code&gt; or &lt;code&gt;intermediate&lt;/code&gt; already filed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Polyglot is shallow.&lt;/strong&gt; JS uses regex, not &lt;code&gt;tree-sitter&lt;/code&gt;. &lt;code&gt;require()&lt;/code&gt; with a variable, &lt;code&gt;dynamic import()&lt;/code&gt;, Go &lt;code&gt;import&lt;/code&gt; blocks, Rust &lt;code&gt;mod&lt;/code&gt; trees — all missed. File: &lt;code&gt;peek/peek/symbols.py&lt;/code&gt; &lt;code&gt;JS_IMPORT_RE&lt;/code&gt; / &lt;code&gt;peek/peek/analyzer.py:300&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokens are &lt;code&gt;len // 4&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;peek --pack --budget 4000&lt;/code&gt; is ~20% off. Swap in &lt;code&gt;tiktoken&lt;/code&gt; &lt;code&gt;cl100k_base&lt;/code&gt; when installed: &lt;code&gt;try: import tiktoken; enc.encode(text)&lt;/code&gt; else fallback. File: &lt;code&gt;peek/peek/pack.py:18&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Help text is keyword-only.&lt;/strong&gt; &lt;code&gt;peek find "auth token"&lt;/code&gt; should use BM25, not &lt;code&gt;q in text.lower()&lt;/code&gt;. The &lt;code&gt;peek/peek/embeddings.py&lt;/code&gt; BM25 index already exists in &lt;code&gt;v3&lt;/code&gt; — wire &lt;code&gt;find.py&lt;/code&gt; to &lt;code&gt;search()&lt;/code&gt; when query has spaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graph is file-level.&lt;/strong&gt; &lt;code&gt;peek graph --format svg&lt;/code&gt; is DOT text wrapped in SVG. A real force-directed canvas in Textual (or &lt;code&gt;dot -Tsvg&lt;/code&gt; if installed) would be the screenshot that beats &lt;code&gt;gitingest&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each has a &lt;strong&gt;one-file, 30-min&lt;/strong&gt; slice and a test that already asserts the current (wrong) behavior — flip the assertion and make it green.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Try It, Break It, Steal It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;peek-code &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; peek &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# TUI: q quit, / filter, t cycle 10 themes, w watch&lt;/span&gt;
peek &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--no-tui&lt;/span&gt; &lt;span class="nt"&gt;--theme&lt;/span&gt; dracula
peek graph &lt;span class="nt"&gt;--format&lt;/span&gt; dot | &lt;span class="nb"&gt;head
&lt;/span&gt;peek find &lt;span class="s2"&gt;"validate_token"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
peek &lt;span class="nt"&gt;--pack&lt;/span&gt; &lt;span class="nt"&gt;--ask&lt;/span&gt; &lt;span class="s2"&gt;"auth"&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; xml &lt;span class="nt"&gt;--budget&lt;/span&gt; 4000 | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
peek wtf &amp;lt; traceback.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;peek&lt;/code&gt; is MIT, &lt;code&gt;analyzer.py&lt;/code&gt; is ~700 lines you can read in one sitting (no &lt;code&gt;networkx&lt;/code&gt;, no ML). If you’ve ever wanted to hack on ranking, graph viz, or “where should an agent look first?” — this is the seam.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good first issues:&lt;/strong&gt; &lt;a href="https://github.com/hariomlohardev/peek/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22" rel="noopener noreferrer"&gt;https://github.com/hariomlohardev/peek/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22&lt;/a&gt; — 20 are &lt;code&gt;good first issue&lt;/code&gt; + &lt;code&gt;help wanted&lt;/code&gt;, each one file, each with &lt;code&gt;### Files&lt;/code&gt; + &lt;code&gt;### Acceptance&lt;/code&gt; checkboxes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discussions:&lt;/strong&gt; What repo should I demo next? What did your &lt;code&gt;peek&lt;/code&gt; map surprise you with? &lt;a href="https://github.com/hariomlohardev/peek/discussions" rel="noopener noreferrer"&gt;https://github.com/hariomlohardev/peek/discussions&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built by &lt;a href="https://hariomlohardev.github.io/" rel="noopener noreferrer"&gt;Hariom Lohar&lt;/a&gt; — &lt;code&gt;peek&lt;/code&gt; is the &lt;code&gt;htop&lt;/code&gt; for codebases. If you liked the ranking rabbit hole, a ⭐ helps more than you think.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>cli</category>
      <category>code</category>
      <category>python</category>
    </item>
    <item>
      <title>I'm Building htop for Codebases in 5 Days — Follow Along</title>
      <dc:creator>Hariom Lohar</dc:creator>
      <pubDate>Mon, 10 Aug 2026 12:54:30 +0000</pubDate>
      <link>https://dev.to/hariomlohardev/im-building-htop-for-codebases-in-5-days-follow-along-283j</link>
      <guid>https://dev.to/hariomlohardev/im-building-htop-for-codebases-in-5-days-follow-along-283j</guid>
      <description>&lt;h2&gt;
  
  
  I'm Building htop for Codebases in 5 Days
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;git clone&lt;/code&gt; ends the same: 47 files, outdated README, 30 mins wasted.&lt;/p&gt;

&lt;p&gt;I'm building &lt;code&gt;peek&lt;/code&gt; — &lt;code&gt;pip install peek &amp;amp;&amp;amp; peek .&lt;/code&gt; → beautiful map in 5 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it will do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What the repo does (auto summary)&lt;/li&gt;
&lt;li&gt;Ranked "Start Here" list&lt;/li&gt;
&lt;li&gt;Import graph&lt;/li&gt;
&lt;li&gt;Tech stack + stats&lt;/li&gt;
&lt;li&gt;Beautiful TUI (Textual) + static mode&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;p&gt;Python, Rich, Textual, AST — ~1k LOC, no bac&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this?
&lt;/h2&gt;

&lt;p&gt;I analyzed 30+ viral dev tools. Formula is universal pain × instant wow × one-liner install. "Codebase map" is the empty slot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeline
&lt;/h2&gt;

&lt;p&gt;Day 1: Scanner → Day 2: Analyzer → Day 3: Beautiful TUI → Day 4: Polish → Day 5: Launch&lt;/p&gt;

&lt;p&gt;Full research done. Code starts tomorrow. Daily updates here.&lt;/p&gt;

&lt;p&gt;Portfolio: &lt;a href="https://hariomlohardev.github.io/" rel="noopener noreferrer"&gt;https://hariomlohardev.github.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What repo should I test it on? Drop a link 👇&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>buildinpublic</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Day 040 — Multi-Head Residual (attention by hand)</title>
      <dc:creator>Hariom Lohar</dc:creator>
      <pubDate>Mon, 10 Aug 2026 05:01:36 +0000</pubDate>
      <link>https://dev.to/hariomlohardev/day-040-multi-head-residual-attention-by-hand-ke5</link>
      <guid>https://dev.to/hariomlohardev/day-040-multi-head-residual-attention-by-hand-ke5</guid>
      <description>&lt;p&gt;Hariom Lohar (hariomlohardev on GitHub) — Lab Notebook No.01 · Day 040 · 10 Aug 2026.&lt;/p&gt;

&lt;p&gt;I rebuilt multi-head attention by hand — no PyTorch, just NumPy. From &lt;code&gt;math → NumPy backprop → CNNs → attention&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Live bench + daily logs: &lt;a href="https://hariomlohardev.github.io" rel="noopener noreferrer"&gt;https://hariomlohardev.github.io&lt;/a&gt;&lt;br&gt;
Full log: &lt;a href="https://hariomlohardev.github.io/blog/p/day-040-multi-head-residual/" rel="noopener noreferrer"&gt;https://hariomlohardev.github.io/blog/p/day-040-multi-head-residual/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Original log on my portfolio (canonical) → &lt;a href="https://hariomlohardev.github.io/blog/p/day-040-multi-head-residual/" rel="noopener noreferrer"&gt;https://hariomlohardev.github.io/blog/p/day-040-multi-head-residual/&lt;/a&gt; — cross-posted to reach more builders. 548 days: 1 Jul 2026 → 31 Dec 2027.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>transformers</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Isn't Jupy looks good , soon be avialabel for opensourse ccontribution</title>
      <dc:creator>Hariom Lohar</dc:creator>
      <pubDate>Sat, 25 Jul 2026 03:05:04 +0000</pubDate>
      <link>https://dev.to/hariomlohardev/isnt-jupy-looks-good-soon-be-avialabel-for-opensourse-ccontribution-3e05</link>
      <guid>https://dev.to/hariomlohardev/isnt-jupy-looks-good-soon-be-avialabel-for-opensourse-ccontribution-3e05</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fth3rc3pv3lylsolijo46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fth3rc3pv3lylsolijo46.png" alt=" " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hey , I am making an opensourse project</title>
      <dc:creator>Hariom Lohar</dc:creator>
      <pubDate>Fri, 24 Jul 2026 02:18:58 +0000</pubDate>
      <link>https://dev.to/hariomlohardev/hey-i-am-making-an-opensourse-project-5goe</link>
      <guid>https://dev.to/hariomlohardev/hey-i-am-making-an-opensourse-project-5goe</guid>
      <description>&lt;p&gt;This is what i am building ,&lt;br&gt;
its opensource soon be available to all devs to contribute on github&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About The Project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is an AI based learning platform right know only for &lt;em&gt;Python&lt;/em&gt;&lt;br&gt;
here you can say AI to make an coding chalange ,wheather its an simple chalange or an Optimization chalange,&lt;br&gt;
AI will help you to give the instrcutions for an Coding chalange &lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
