<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: HarmanPreet-Singh-XYT</title>
    <description>The latest articles on Forem by HarmanPreet-Singh-XYT (@harmanpreetsingh).</description>
    <link>https://forem.com/harmanpreetsingh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1191004%2Fe1592bcd-0a31-48c0-a921-ad7b89f11835.jpeg</url>
      <title>Forem: HarmanPreet-Singh-XYT</title>
      <link>https://forem.com/harmanpreetsingh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/harmanpreetsingh"/>
    <language>en</language>
    <item>
      <title>How CodiLay Reads a Codebase the Way a Detective Reads a Crime Scene</title>
      <dc:creator>HarmanPreet-Singh-XYT</dc:creator>
      <pubDate>Thu, 19 Mar 2026 07:39:35 +0000</pubDate>
      <link>https://forem.com/harmanpreetsingh/how-codilay-reads-a-codebase-the-way-a-detective-reads-a-crime-scene-3lml</link>
      <guid>https://forem.com/harmanpreetsingh/how-codilay-reads-a-codebase-the-way-a-detective-reads-a-crime-scene-3lml</guid>
      <description>&lt;p&gt;Most documentation tools ask you to write the docs yourself, or they generate something so shallow it barely survives contact with the actual codebase. CodiLay takes a different approach. It reads the code the way an investigator reads evidence — tracing connections, holding open questions, resolving them when the right file comes along, and building a picture that gets more accurate as it goes.&lt;/p&gt;

&lt;p&gt;Here's how it actually works under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Wire Model
&lt;/h2&gt;

&lt;p&gt;The central abstraction in CodiLay is the &lt;strong&gt;wire&lt;/strong&gt;. A wire represents an unresolved reference — a file imports something, calls something, or depends on something that hasn't been documented yet. The agent opens a wire when it sees the reference. That wire stays alive in the agent's active state, carried forward through subsequent files, until a later file explains the other end. At that point, the wire closes, the connection gets recorded, and it retires from active context permanently.&lt;/p&gt;

&lt;p&gt;This is deliberate. Closed wires are never re-injected into future LLM calls. As the codebase grows, the active context stays lean — only what's genuinely unresolved travels forward.&lt;/p&gt;

&lt;p&gt;Wires carry type information too. &lt;code&gt;import&lt;/code&gt;, &lt;code&gt;call&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;config&lt;/code&gt;, &lt;code&gt;event&lt;/code&gt;. A routes file importing a service opens an &lt;code&gt;import&lt;/code&gt; wire. That service calling into a payment processor opens a &lt;code&gt;call&lt;/code&gt; wire. Wires that reach external packages or reference deleted files stay permanently open and surface in the final output as &lt;strong&gt;Unresolved References&lt;/strong&gt; — which is useful information, not a failure.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Agent Loop, Phase by Phase
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bootstrap&lt;/strong&gt; strips the project down to what matters: parse &lt;code&gt;.gitignore&lt;/code&gt;, merge any additional ignore patterns from config, walk the directory tree, preload existing markdown files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Triage&lt;/strong&gt; is a single LLM call that sees only filenames and paths, not file content. It categorizes every file as &lt;code&gt;core&lt;/code&gt; (document fully), &lt;code&gt;skim&lt;/code&gt; (extract key metadata), or &lt;code&gt;skip&lt;/code&gt; (ignore entirely). For a Flutter project this means &lt;code&gt;ios/&lt;/code&gt;, &lt;code&gt;android/&lt;/code&gt;, &lt;code&gt;build/&lt;/code&gt;, and all generated &lt;code&gt;.g.dart&lt;/code&gt; and &lt;code&gt;.freezed.dart&lt;/code&gt; files disappear before the planner ever sees them. For a Next.js project, &lt;code&gt;.next/&lt;/code&gt; and &lt;code&gt;out/&lt;/code&gt; vanish. The triage phase is autonomous — no user confirmation step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Planning&lt;/strong&gt; makes one LLM call against the curated (post-triage) file list. The planner outputs an ordered queue, a list of parked files (too ambiguous to process yet), and a suggested document skeleton including section names and structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Processing&lt;/strong&gt; runs file by file through that queue. For each file, the agent counts tokens with &lt;code&gt;tiktoken&lt;/code&gt;, decides whether it goes through single-call or large-file handling, loads the relevant doc chunks, builds a prompt with current wire state and section index, calls the LLM, applies the JSON diff to the docstore, and updates the wire state — closing resolved wires, opening new ones, checking whether any parked files can now be unparked given the new context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finalization&lt;/strong&gt; runs a sequential sweep with full wire context. Parked files get documented with whatever context exists. The Unresolved References and Dependency Graph sections assemble. &lt;code&gt;CODEBASE.md&lt;/code&gt; writes out. &lt;code&gt;links.json&lt;/code&gt; writes out. The current HEAD commit hash saves to state for the next re-run.&lt;/p&gt;




&lt;h2&gt;
  
  
  Large File Handling
&lt;/h2&gt;

&lt;p&gt;Files are measured in tokens, not lines. A 500-line TypeScript generics file costs more context than a 1,000-line config file. The default threshold is 6,000 tokens, configurable per project.&lt;/p&gt;

&lt;p&gt;Files over the threshold go through a skeleton pass first. The agent reads imports, function signatures, class definitions, and docstrings — no function bodies. This builds the section in the docstore, opens all detectable wires early, and marks the section as &lt;code&gt;detail_pending&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then the file splits along natural boundaries — class definitions, top-level functions, component edges. If no clean boundaries exist, it splits by token budget with 10–15% overlap between chunks. The overlap is the key detail. Without it, a function that starts at the bottom of chunk N and ends at the top of chunk N+1 gets half-documented or missed entirely. Overlap means the model always has trailing context from the previous chunk.&lt;/p&gt;

&lt;p&gt;The skeleton-first order matters for a reason beyond chunking. By the time detail passes run, other files in the queue may have already processed. The LLM reading a function body already knows what calls it and what it returns to — it reads with full context rather than in isolation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Docstore Architecture
&lt;/h2&gt;

&lt;p&gt;The docstore manages the document as independently addressable sections rather than a flat string. Each section carries invisible metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- section:id=auth-middleware tags=auth,jwt,middleware deps=routes/users.js,routes/orders.js --&amp;gt;&lt;/span&gt;
&lt;span class="gu"&gt;## Auth Middleware&lt;/span&gt;
...content...
&lt;span class="c"&gt;&amp;lt;!-- /section --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These markers strip on final output. The section index — a lightweight JSON object always in context — holds only metadata: title, file, tags, deps, which wires it closed, whether it's &lt;code&gt;detail_pending&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When processing a new file, relevant sections load by priority: sections whose &lt;code&gt;deps&lt;/code&gt; list includes the current file path, sections whose tags overlap with imports found in the current file, sections flagged by open wires pointing to this file, and the top-level Overview (always loaded). Each LLM call stays bounded regardless of total document size.&lt;/p&gt;




&lt;h2&gt;
  
  
  Structured Parallelism
&lt;/h2&gt;

&lt;p&gt;Sequential processing of a 50-file codebase means 50 serial LLM calls. Naive parallelism breaks the wire model — two workers processing related files simultaneously produce inconsistent context and miss connections.&lt;/p&gt;

&lt;p&gt;CodiLay solves this with a dependency tier model. Before the loop starts, the planner builds a lightweight DAG from structural inference (folder hierarchy, import patterns visible in skim files). Files assign to tiers by their depth in the DAG. Tier 0 is entry points. Tier 1 is files directly imported by tier 0. And so on.&lt;/p&gt;

&lt;p&gt;Processing happens tier by tier. Within a tier, all files run in parallel. Between tiers, a hard sync point waits for all workers to finish and reconciles the central wire bus before the next tier begins.&lt;/p&gt;

&lt;p&gt;The wire bus is the shared state that makes safe parallelism possible. All workers read from and write to it through atomic operations: &lt;code&gt;open(wire)&lt;/code&gt;, &lt;code&gt;close(wire_id, summary)&lt;/code&gt;, &lt;code&gt;peek(file_path)&lt;/code&gt;, &lt;code&gt;mark_pending(wire_id)&lt;/code&gt;. Individual doc sections write independently per worker — only wire state is shared and locked.&lt;/p&gt;

&lt;p&gt;Every worker takes a frozen snapshot of the wire bus at job start. It processes its file against that snapshot, not a live-updating view. A wire that closes mid-call by another worker doesn't affect the current worker's LLM call. The finalize pass reconciles everything afterward.&lt;/p&gt;

&lt;p&gt;Sections generated during parallel processing carry a confidence tag: &lt;code&gt;partial&lt;/code&gt; if there were pending wires at generation time. The finalize pass always re-reviews &lt;code&gt;partial&lt;/code&gt; sections. Speedup expectations range from 1.5x on deep call-chain monoliths to 5–8x on flat utility repos.&lt;/p&gt;




&lt;h2&gt;
  
  
  Git Integration
&lt;/h2&gt;

&lt;p&gt;The current HEAD commit hash saves to state after every run. On the next run, &lt;code&gt;git diff &amp;lt;last_commit&amp;gt; HEAD --name-status&lt;/code&gt; returns a typed change list — &lt;code&gt;M&lt;/code&gt; for modified, &lt;code&gt;A&lt;/code&gt; for added, &lt;code&gt;D&lt;/code&gt; for deleted, &lt;code&gt;R&lt;/code&gt; for renamed.&lt;/p&gt;

&lt;p&gt;Modified files re-enter the queue. Any wires that originated from or pointed to them re-open. Their doc sections invalidate. Added files run through a single-file triage call before queuing. Deleted files turn their wires permanently open with a note referencing the commit hash. Renamed files get all their wire &lt;code&gt;from&lt;/code&gt;/&lt;code&gt;to&lt;/code&gt; fields updated along with section index &lt;code&gt;deps&lt;/code&gt; entries, then re-process at the new path.&lt;/p&gt;

&lt;p&gt;When git isn't available — no git history, no git binary — the fallback compares file mtimes against timestamps in the state file. Files newer than &lt;code&gt;last_run&lt;/code&gt; treat as modified. Files in &lt;code&gt;processed&lt;/code&gt; but missing from disk treat as deleted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Parallelism Safety: Three Failure Modes Eliminated
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Missed wire&lt;/strong&gt; — Worker B documents a file without knowing Worker A opened a wire pointing to it. The wire never closes. The connection disappears from the final doc. The frozen-context snapshot eliminates this: every worker reads the wire bus before starting, and the finalize pass catches anything that slipped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Partial read&lt;/strong&gt; — Worker B reads shared wire state mid-update by Worker A, gets half-formed context, and produces inconsistent output. The locked atomic operations on the wire bus eliminate this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confident wrong&lt;/strong&gt; — Worker B has no open wire pointing to its file, assumes self-containment, and hallucinates relationships. The confidence tagging catches this: if pending wires existed at generation time, the section marks as &lt;code&gt;partial&lt;/code&gt; and finalize re-reviews it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resumption and Cost Protection
&lt;/h2&gt;

&lt;p&gt;The state file rotates through four copies: current, &lt;code&gt;.bak.1&lt;/code&gt;, &lt;code&gt;.bak.2&lt;/code&gt;, &lt;code&gt;.bak.3&lt;/code&gt;. On corruption, automatic fallback cascades through the backups. State files run 50–200KB — negligible disk footprint.&lt;/p&gt;

&lt;p&gt;The LLM response cache is the deepest money protection. Before any LLM call, the system checks for a cached response keyed on &lt;code&gt;hash(file_content) + hash(prompt_template) + hash(wire_context_snapshot)&lt;/code&gt;. A crash between API call and docstore write doesn't lose the money — the response is in cache and replays on resume at zero cost.&lt;/p&gt;

&lt;p&gt;The two-phase docstore write ensures this: write LLM response to cache (atomic), write section to temp file, atomically move to final location via &lt;code&gt;os.replace()&lt;/code&gt;, update state, rotate backups. A crash at any step after the cache write means the response survives.&lt;/p&gt;

&lt;p&gt;Failure routing distinguishes retryable from user-actionable errors. Rate limits get exponential backoff with jitter, up to 5 retries. Timeouts retry once with a longer timeout, then park. Auth errors pause the run and prompt the user to fix the API key — then resume. Disk full pauses and waits. The distinction matters: retrying an auth error silently accomplishes nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Web UI Architecture
&lt;/h2&gt;

&lt;p&gt;The server is a FastAPI application built with a factory pattern — &lt;code&gt;create_app(target_path, output_dir)&lt;/code&gt; scopes the entire app to a specific project via closures. All state is project-local.&lt;/p&gt;

&lt;p&gt;Four items cache with mtime invalidation: agent state, wire links, &lt;code&gt;CODEBASE.md&lt;/code&gt;, and the TF-IDF retriever. When &lt;code&gt;codilay run&lt;/code&gt; or &lt;code&gt;codilay watch&lt;/code&gt; updates files on disk, the server picks up changes without restart.&lt;/p&gt;

&lt;p&gt;All synchronous operations — LLM calls, file I/O, search indexing — wrap in &lt;code&gt;asyncio.to_thread&lt;/code&gt; to keep the async event loop responsive under concurrent requests. Feature modules lazy-import inside their endpoint handlers rather than at module level, which keeps startup fast and isolates import errors.&lt;/p&gt;

&lt;p&gt;The chat system runs three layers. Layer 1 renders the static output with an interactive dependency graph from &lt;code&gt;links.json&lt;/code&gt;. Layer 2 is a chatbot that answers questions from doc context only. Layer 3, the deep agent, activates when confidence drops below threshold — it reads actual source files, answers with precision, then patches the doc with what it found. The next time the same question arrives, Layer 2 handles it without escalation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code Annotation
&lt;/h2&gt;

&lt;p&gt;The annotation system writes wire knowledge back into source files as comments and docstrings. It's the one feature that modifies actual code, which drives the guard design.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;requireGitClean&lt;/code&gt; blocks annotation if the working tree has uncommitted changes. &lt;code&gt;git checkout .&lt;/code&gt; always works as a clean rollback. &lt;code&gt;requireDryRunFirst&lt;/code&gt; forces a dry run on the first annotation of any project — nothing writes until the user has seen the unified diff preview.&lt;/p&gt;

&lt;p&gt;Annotations insert sorted by line number descending — bottom of file first. This prevents line offset drift. Inserting a block comment at line 10 shifts every subsequent target line number by N. Inserting from the bottom up means each insertion doesn't affect anything above it.&lt;/p&gt;

&lt;p&gt;Before writing any file, syntax validation runs. Python goes through &lt;code&gt;ast.parse()&lt;/code&gt;. Other languages get structural checks. If validation fails, the original file stays untouched and the annotation moves to the review queue.&lt;/p&gt;

&lt;p&gt;The wire connection block in an annotation is the output that no other doc generator produces:&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;process_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retry_count&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Charges the customer for a pending order via Stripe.

    Wire connections:
      &amp;lt;- Called by: routes/orders.py (checkout), scheduler/retry_jobs.py
      -&amp;gt; Calls:     stripe.charge.create, notify_fulfillment (Celery task)
      -&amp;gt; Reads:     Order model, Customer.stripe_id

    Retry logic: up to 3 attempts with exponential backoff.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cross-file relationship shows up directly in the code, not in a separate document that drifts out of sync.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conversation Search
&lt;/h2&gt;

&lt;p&gt;The search module is a custom TF-IDF implementation with no external dependencies. It tokenizes with a regex that extracts words and code identifiers (&lt;code&gt;get_user&lt;/code&gt;, &lt;code&gt;handleClick&lt;/code&gt;) while filtering stop words. Augmented TF — &lt;code&gt;0.5 + 0.5 * (term_count / max_term_in_doc)&lt;/code&gt; — prevents long documents from dominating by raw occurrence count. IDF uses &lt;code&gt;log((1 + N) / (1 + df)) + 1&lt;/code&gt; smoothing so terms appearing in all documents don't score to zero.&lt;/p&gt;

&lt;p&gt;Snippets extract by scanning for the 120-character window with highest query term density, which ensures the most relevant part of a message shows rather than just the opening.&lt;/p&gt;

&lt;p&gt;The index saves to &lt;code&gt;codilay/chat/search_index.json&lt;/code&gt;. It's a non-critical cache — if missing or corrupt, it auto-rebuilds from conversation files. First search after fresh install is slower; everything after uses the cached index.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Audit System
&lt;/h2&gt;

&lt;p&gt;Audits run against the wire graph and doc context with a specific analytical lens. The wire model already knows where auth happens, what touches it, where data enters and exits, what depends on what, where secrets get referenced. An audit agent reads this existing knowledge and does targeted deep dives into the files relevant to the audit type.&lt;/p&gt;

&lt;p&gt;Every finding includes the wire path that shows how the vulnerable code gets reached:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FINDING: Unsanitized user input in search handler
Severity:   HIGH
File:       src/routes/search.js  line 47
Wire path:  routes/search.js -&amp;gt; utils/query_builder.js (call)
Evidence:   req.query.term passed directly to buildQuery() with no sanitization
Impact:     buildQuery() constructs raw SQL — potential injection
Fix:        Sanitize req.query.term before passing to buildQuery()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The checklist system matters here. Each audit type loads a specific checklist into the system prompt. The LLM works through it item by item rather than free-associating. Nothing gets skipped, and every finding ties to a specific checklist item.&lt;/p&gt;

&lt;p&gt;Audit types split into three tiers. Tier 1 is pure code analysis — security, architecture, performance, dependency supply chain, license audit. CodiLay reads the code and produces findings. Tier 2 adds config file analysis — Dockerfiles, CI pipelines, IAM definitions, cloud resource config. Tier 3 generates specifications for external tooling — OWASP ZAP target lists from route wires, load test targets from high-traffic route analysis, chaos engineering blast radius maps from the dependency graph.&lt;/p&gt;

&lt;p&gt;Multiple audit types share file reads in one pass. A security and architecture audit running together surfaces things neither finds alone — a service boundary violation that also creates a security exposure.&lt;/p&gt;




&lt;p&gt;CodiLay sits at ~30k lines across ~25+ source files, 500+ passing tests, and 30+ CLI commands. The wire model is the idea everything else builds on. Everything from parallelism to audit reports to annotation safety to cost protection traces back to the same core abstraction: track what you know, track what you don't, resolve unknowns as you go, and never carry dead weight into the next call.&lt;/p&gt;

&lt;p&gt;Website - &lt;a href="https://codilay.harmanita.com" rel="noopener noreferrer"&gt;codilay.harmanita.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>rag</category>
      <category>documentation</category>
    </item>
    <item>
      <title>The AI That Reads Your Codebase Like a Detective</title>
      <dc:creator>HarmanPreet-Singh-XYT</dc:creator>
      <pubDate>Mon, 16 Mar 2026 04:09:19 +0000</pubDate>
      <link>https://forem.com/harmanpreetsingh/the-ai-that-reads-your-codebase-like-a-detective-4c5a</link>
      <guid>https://forem.com/harmanpreetsingh/the-ai-that-reads-your-codebase-like-a-detective-4c5a</guid>
      <description>&lt;p&gt;Every engineering team has that one project. The one where no one knows exactly what &lt;code&gt;lib/helpers.js&lt;/code&gt; does. The one where onboarding takes two weeks because the documentation is a six-year-old Confluence page with broken screenshots. The one where you open the repo and feel the weight of someone else's decisions pressing down on you.&lt;/p&gt;

&lt;p&gt;CodiLay starts from the belief that documentation has to be generated, not written — and that the generator should think like an investigator, not a summarizer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A detective doesn't read a crime scene and produce a bullet-point list. They trace the wires."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Reading code the way a human does
&lt;/h2&gt;

&lt;p&gt;When an experienced engineer explores a new codebase, they don't read files alphabetically. They find the entry point, follow the imports, note what they haven't seen yet, and circle back. CodiLay replicates this exact behavior through a mechanism called &lt;em&gt;wires&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A wire opens the moment the agent encounters something it hasn't documented yet — an imported module, a called service, an unknown dependency. That wire gets tracked, carried forward in active memory, and prioritized. The agent reorders its reading queue around it. When a later file finally explains the other end of that reference, the wire closes, the link gets recorded, and it retires from memory permanently.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OPEN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reference seen, target unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLOSED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Both ends documented, link formed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Closed wires never re-enter the LLM context. This matters more than it sounds. Most documentation agents bloat their prompts as the codebase grows. CodiLay's context window stays lean by design — each LLM call only carries what's genuinely unresolved.&lt;/p&gt;




&lt;h2&gt;
  
  
  Triage before analysis
&lt;/h2&gt;

&lt;p&gt;The first thing CodiLay does after reading the file tree is triage. A single LLM call looks at filenames and paths — no file content — and categorizes everything into three buckets: &lt;code&gt;core&lt;/code&gt;, &lt;code&gt;skim&lt;/code&gt;, and &lt;code&gt;skip&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A Flutter project, for example, gets its &lt;code&gt;ios/&lt;/code&gt;, &lt;code&gt;android/&lt;/code&gt;, and &lt;code&gt;build/&lt;/code&gt; folders automatically moved to skip. The agent recognizes standard scaffolding and doesn't waste budget analyzing generated code. You get to review the triage decision before anything else runs.&lt;/p&gt;

&lt;p&gt;Then the planner takes over — another single LLM call, this time with the curated file list — and produces a reading order. Files get ranked by how many open wires they're likely to close. The ones with no context yet go into a parked queue and get unparked as more of the codebase becomes clear.&lt;/p&gt;




&lt;h2&gt;
  
  
  Big files don't break it
&lt;/h2&gt;

&lt;p&gt;Files over 6,000 tokens get a two-pass treatment. The first pass extracts only symbols and docstrings, builds a skeleton, and surfaces whatever wires are detectable from the shape of the code. The second pass reads the actual implementation chunk by chunk, filling in the skeleton with real understanding.&lt;/p&gt;

&lt;p&gt;The threshold is configurable. The logic — read the shape before reading the substance — stays constant.&lt;/p&gt;




&lt;h2&gt;
  
  
  What comes out the other end
&lt;/h2&gt;

&lt;p&gt;The final output is a &lt;code&gt;CODEBASE.md&lt;/code&gt; — a living document with an overview, component sections for every file, a dependency graph rendered as a table, and an Unresolved References section that surfaces whatever wires stayed open at the end of the run.&lt;/p&gt;

&lt;p&gt;That last section is genuinely useful. Open wires that point to external packages are expected. Open wires that point inward — to files that should exist but don't — are potential dead code or missing modules. The agent hands you the signal. What you do with it is up to you.&lt;/p&gt;

&lt;p&gt;A machine-readable &lt;code&gt;links.json&lt;/code&gt; comes alongside it — a dependency graph you can query, render, or feed into other tools.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the run ends, the current git commit hash gets stored. Next time you run CodiLay, only the changed files get re-analyzed.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The web layer on top
&lt;/h2&gt;

&lt;p&gt;Beyond the CLI, CodiLay ships with a web reader that turns the generated documentation into an interactive interface. At the base layer, it renders &lt;code&gt;CODEBASE.md&lt;/code&gt; and the dependency graph statically. Above that, a chatbot answers questions scoped to the documentation context. When the documentation doesn't have the answer, a deeper agent escalates directly to the source code.&lt;/p&gt;

&lt;p&gt;Any insight the deep agent surfaces gets patched back into the permanent doc. The documentation improves itself through use.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it's built from
&lt;/h2&gt;

&lt;p&gt;The core is Python 3.10+. Token counting runs through tiktoken. The CLI renders through Rich. A FastAPI backend serves the web UI and chat endpoints. Gitignore parsing uses pathspec for full glob compatibility. The LLM layer wraps a unified interface over multiple providers — the underlying model is swappable through config.&lt;/p&gt;




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

&lt;p&gt;Documentation tools tend to fall into one of two failure modes: they're too shallow to be useful, or they require so much setup that no one uses them. CodiLay's bet is that a system designed around genuine code comprehension — not just summarization — produces output worth the setup cost.&lt;/p&gt;

&lt;p&gt;The wire model is the foundation of that bet. Treat every unknown as something to be resolved, carry only what's unresolved, and retire knowledge the moment it's complete. That's the circuit. CodiLay traces it until the map is done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HarmanPreet-Singh-XYT/codilay" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>developertools</category>
      <category>documentation</category>
      <category>llm</category>
      <category>codebase</category>
    </item>
    <item>
      <title>What Building Two Gemini-Powered Apps Taught Me About AI, Tokens, and Scope Discipline</title>
      <dc:creator>HarmanPreet-Singh-XYT</dc:creator>
      <pubDate>Tue, 03 Mar 2026 02:35:03 +0000</pubDate>
      <link>https://forem.com/harmanpreetsingh/what-building-two-gemini-powered-apps-taught-me-about-ai-tokens-and-scope-discipline-5e4o</link>
      <guid>https://forem.com/harmanpreetsingh/what-building-two-gemini-powered-apps-taught-me-about-ai-tokens-and-scope-discipline-5e4o</guid>
      <description>&lt;h1&gt;
  
  
  From Hackathon to Impact: What I Built with Google Gemini
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/mlh/built-with-google-gemini-02-25-26"&gt;Built with Google Gemini: Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built with Google Gemini
&lt;/h2&gt;

&lt;p&gt;I didn't build one thing with Google Gemini — I built two, each solving a completely different human problem. And honestly, that contrast is what made this experience so valuable.&lt;/p&gt;




&lt;h3&gt;
  
  
  Project 1: SunRes — The Resume That Actually Gets You the Interview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; Most people apply for jobs the same way — they spray one resume across dozens of listings and wonder why they never hear back. The resume isn't bad. It's just &lt;em&gt;wrong&lt;/em&gt; for the job. Mismatched keywords. Missing skills. Sections that ATS systems silently reject before a human ever sees them.&lt;/p&gt;

&lt;p&gt;I've felt this personally as a student applying for internships. So I built SunRes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SunRes isn't just a resume generator — it's a &lt;em&gt;mismatch engine&lt;/em&gt;. Users build a master profile (all their projects, skills, achievements), then paste in a job description. Gemini then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parses the uploaded resume to auto-fill their profile&lt;/li&gt;
&lt;li&gt;Analyzes the job description to extract what the company actually wants&lt;/li&gt;
&lt;li&gt;Generates a job–profile match score and &lt;em&gt;explains why&lt;/em&gt; the user might get rejected&lt;/li&gt;
&lt;li&gt;Suggests targeted fixes to close those gaps&lt;/li&gt;
&lt;li&gt;Auto-selects the most relevant projects and achievements for that specific role&lt;/li&gt;
&lt;li&gt;Generates a tailored resume and cover letter&lt;/li&gt;
&lt;li&gt;Lets users refine everything through a chatbot interface before downloading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight: one profile, infinite tailored resumes. You never start from scratch again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; Next.js · FastAPI · PostgreSQL · Google Gemini API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=ghgJiWWdxfM" rel="noopener noreferrer"&gt;Watch it in action →&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Project 2: NorthStar — A Lifeline for People in Crisis
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Problem:&lt;/strong&gt; When someone is in a genuine crisis — no food, no shelter, a medical emergency — they don't need a cluttered Google search. They need the nearest food bank, the nearest emergency shelter, the nearest free clinic. Right now. Standard map apps prioritize commercial results. That's not good enough.&lt;/p&gt;

&lt;p&gt;NorthStar strips away the noise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using the browser's Location API, NorthStar instantly surfaces the most relevant community resources nearby — organized into four categories: Health, Shelter, Sustenance, and Support. A custom semantic mapping system on the backend translates simple icon clicks into precise, filtered queries (e.g., "Shelters" → &lt;code&gt;"homeless shelter emergency housing"&lt;/code&gt;), cutting through commercial noise to surface the places that actually help.&lt;/p&gt;

&lt;p&gt;But finding the resource is only half the battle. Once you see a result — a shelter, a clinic, a food bank — you immediately have follow-up questions. &lt;em&gt;Is it wheelchair accessible? What are the hours? Do they take walk-ins?&lt;/em&gt; That's where Gemini comes in. NorthStar has a built-in Gemini-powered chat on each result, so users can ask natural questions about any location and get instant, contextual answers — without leaving the app or opening a new search.&lt;/p&gt;

&lt;p&gt;The goal: from crisis moment to actionable resource in under two seconds, with the context you need to actually show up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; React.js · Python/FastAPI · Google Maps &amp;amp; Places APIs · Google Gemini API · Google Cloud&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=CbdO2o3ZIQU" rel="noopener noreferrer"&gt;Watch it in action →&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;These two projects taught me different things, and I think that's worth unpacking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SunRes taught me that AI is most powerful when it &lt;em&gt;explains&lt;/em&gt;, not just executes.&lt;/strong&gt; Early versions just generated a resume. That felt hollow — like magic with no instruction manual. The breakthrough was making Gemini articulate &lt;em&gt;why&lt;/em&gt; a profile was a weak match and &lt;em&gt;what specifically&lt;/em&gt; needed to change. That transparency turned a tool into a coach. Users didn't just get an output; they understood their problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NorthStar taught me that infrastructure is a product feature.&lt;/strong&gt; We spent real time on IAM permissions, API key restrictions, and quota management in Google Cloud Console. That's not glamorous work, but it's what makes something actually deployable and sustainable. Security isn't a post-launch task — it's part of the build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Both projects taught me scope discipline.&lt;/strong&gt; Hackathon timelines are brutal. The features you &lt;em&gt;don't&lt;/em&gt; build matter as much as the ones you do. Knowing when to stop is a skill.&lt;/p&gt;

&lt;p&gt;And perhaps most unexpectedly: &lt;strong&gt;clear storytelling matters as much as clean code.&lt;/strong&gt; A product that people understand and feel connected to will always outperform a technically superior one that nobody gets.&lt;/p&gt;




&lt;h2&gt;
  
  
  Google Gemini Feedback
&lt;/h2&gt;

&lt;p&gt;I'll be candid here, because I think honest feedback is more useful than praise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NorthStar (smooth experience):&lt;/strong&gt; Gemini plays a direct user-facing role here — once someone finds a resource on the map, they can ask Gemini questions about it right on the page: accessibility, working hours, walk-in availability, and so on. The queries are focused and conversational, the responses are short and practical, and it just... worked. Clean outputs, fast responses, no friction. When the scope of what you're asking Gemini is well-defined and contained, it really shines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SunRes (where things got real):&lt;/strong&gt; SunRes pushed Gemini much harder. The pipeline was: parse a resume → extract structured profile data → analyze a job description → cross-reference both → generate scored feedback with reasoning → produce a tailored resume → write a cover letter. That's a lot of tokens per request, and I hit walls.&lt;/p&gt;

&lt;p&gt;The honest truth: I misconfigured my &lt;code&gt;max_tokens&lt;/code&gt; values. I set them too conservatively early on, and responses were getting truncated mid-output — which broke my structured JSON parsing downstream and caused some ugly cascading failures. Once I understood the actual token budget I needed per stage and set appropriate limits, things stabilized.&lt;/p&gt;

&lt;p&gt;Was it a Gemini problem? Not really. It was a &lt;em&gt;me&lt;/em&gt; problem — I underestimated what I was asking for. But it did surface something worth noting: when you're building multi-step AI pipelines, token budgeting isn't an afterthought. It's architecture. I'd love better built-in tooling or clearer documentation around estimating token usage for complex, chained prompts.&lt;/p&gt;

&lt;p&gt;What worked exceptionally well in Gemini: &lt;strong&gt;structured reasoning over ambiguous inputs.&lt;/strong&gt; Resumes come in wildly different formats. Job descriptions are inconsistently written. Gemini handled both with a reliability I didn't fully expect — extracting structured data from messy, real-world documents without me needing to write elaborate parsing logic. That was genuinely impressive and saved significant development time.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SunRes:&lt;/strong&gt; I want to track application outcomes so the match scoring improves over time with real feedback loops. Interview prep tools based on what's actually on the user's resume. Integration with job boards. Skill-gap learning recommendations. The goal is to take candidates from &lt;em&gt;application → interview → offer&lt;/em&gt; — not just hand them a prettier PDF.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NorthStar:&lt;/strong&gt; More resource categories, community-contributed listings to keep data current, and offline capability for users in areas with poor connectivity. The people who need this most are often the people with the worst internet access. That feels like the right problem to solve next.&lt;/p&gt;




&lt;p&gt;Building with Gemini forced me to think about AI not as a black box that produces outputs, but as a reasoning layer that can explain its work, handle messy real-world data, and fit into larger product pipelines. That mental shift — from &lt;em&gt;AI as autocomplete&lt;/em&gt; to &lt;em&gt;AI as collaborator&lt;/em&gt; — is what I'm taking forward.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>geminireflections</category>
      <category>gemini</category>
    </item>
    <item>
      <title>How Google Search Pagination Works: A Developer's Deep Dive</title>
      <dc:creator>HarmanPreet-Singh-XYT</dc:creator>
      <pubDate>Mon, 28 Jul 2025 16:19:24 +0000</pubDate>
      <link>https://forem.com/harmanpreetsingh/how-google-search-pagination-works-a-developers-deep-dive-4lmo</link>
      <guid>https://forem.com/harmanpreetsingh/how-google-search-pagination-works-a-developers-deep-dive-4lmo</guid>
      <description>&lt;p&gt;As developers, we often take pagination for granted—those simple "Next" and "Previous" buttons at the bottom of search results. But when you're dealing with billions of web pages and millions of queries per second like Google does, pagination becomes a fascinating engineering challenge. Let's explore how this actually works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Pagination, Really?
&lt;/h2&gt;

&lt;p&gt;Imagine you walk into the world's largest library and ask for "all books about cooking." The librarian could dump 10 million books on your desk, but that would crush you (literally). Instead, they bring you 10 books at a time. You can ask for the next 10 whenever you're ready. That's pagination—breaking large amounts of data into digestible chunks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Traditional Way vs. Google's Reality
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How Most Websites Do It
&lt;/h3&gt;

&lt;p&gt;Think of a regular website like a small bookstore. When you search for "mystery novels," the store:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Counts all 500 mystery books&lt;/li&gt;
&lt;li&gt;Shows you books 1-10 on page 1&lt;/li&gt;
&lt;li&gt;When you click page 2, it shows books 11-20&lt;/li&gt;
&lt;li&gt;Simple and straightforward&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Google's Challenge
&lt;/h3&gt;

&lt;p&gt;Now imagine you're not dealing with 500 books, but 100 billion web pages. And instead of one person asking for books, you have 100,000 people asking every second, each wanting different books in different languages, from different locations.&lt;/p&gt;

&lt;p&gt;Suddenly, that simple counting method breaks down completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Distributed Library System
&lt;/h2&gt;

&lt;p&gt;Google doesn't have one giant computer holding all web pages. Instead, think of it like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Mega-Library Analogy&lt;/strong&gt;: &lt;br&gt;
Imagine splitting that massive library into 1,000 smaller libraries spread across the world. When you search for "pizza recipes":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your request goes to a head librarian (query processor)&lt;/li&gt;
&lt;li&gt;The head librarian shouts your request to all 1,000 libraries simultaneously&lt;/li&gt;
&lt;li&gt;Each library quickly finds their best pizza recipe books&lt;/li&gt;
&lt;li&gt;All libraries report back their top 10 books&lt;/li&gt;
&lt;li&gt;The head librarian picks the absolute best 10 from those 10,000 options&lt;/li&gt;
&lt;li&gt;You see these as your first page of results&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Deep Pagination Problem
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. What happens when you click on page 50 of Google results?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Stadium Analogy&lt;/strong&gt;: &lt;br&gt;
Imagine you're looking for the 500th tallest person in a packed football stadium:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can't just skip to person #500&lt;/li&gt;
&lt;li&gt;You need to measure everyone, rank them by height, then find who's #500&lt;/li&gt;
&lt;li&gt;Even worse, people keep entering and leaving the stadium (new web pages appear/disappear)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why Google shows "About 2,340,000 results" but won't actually let you click through to page 234,000. It would require ranking millions of results just to show you 10 of them—computationally insane!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Clever Workarounds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The Snapshot Approach
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Restaurant Menu Analogy&lt;/strong&gt;: &lt;br&gt;
When you search, Google takes a "snapshot" of results at that moment—like photographing a restaurant's daily specials board. Even if the specials change 5 minutes later, you're still looking at that original photo as you flip through pages. This ensures consistency but means you might miss super-fresh content.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Priority System
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Emergency Room Triage&lt;/strong&gt;: &lt;br&gt;
Just like hospitals prioritize critical patients, Google prioritizes computing results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First page: Computed with maximum effort (like treating critical patients)&lt;/li&gt;
&lt;li&gt;Pages 2-5: Still high priority (urgent care)&lt;/li&gt;
&lt;li&gt;Pages 10+: Lower priority (regular checkup)&lt;/li&gt;
&lt;li&gt;Page 50+: "Are you sure you need this?" (elective procedure)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. The Estimation Game
&lt;/h3&gt;

&lt;p&gt;When Google says "About 45,700,000 results," they're not actually counting. It's like estimating crowd size at a concert:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look at a small section&lt;/li&gt;
&lt;li&gt;Count people in that section&lt;/li&gt;
&lt;li&gt;Multiply by the total area&lt;/li&gt;
&lt;li&gt;Give an approximate number&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's good enough for users to understand the scale, without counting every single person.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You Can't Go Past Page 40-50
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Highway Analogy&lt;/strong&gt;: &lt;br&gt;
Imagine a highway system where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;90% of drivers exit in the first 5 miles (pages 1-5)&lt;/li&gt;
&lt;li&gt;9% exit in miles 5-20 (pages 5-20)&lt;/li&gt;
&lt;li&gt;Only 1% go further&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Would you build and maintain a 1,000-mile highway for that 1%? Google makes the same calculation—it's not worth the computational cost to support deep pagination when almost nobody uses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Trade-offs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Speed vs. Completeness
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pizza Delivery Analogy&lt;/strong&gt;: &lt;br&gt;
You can either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deliver hot pizza to 99% of customers in 30 minutes&lt;/li&gt;
&lt;li&gt;Or deliver to 100% of customers, but everyone waits 2 hours&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google chooses speed for the majority over completeness for everyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Freshness vs. Consistency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;News Stand Analogy&lt;/strong&gt;: &lt;br&gt;
When you're browsing newspapers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Option 1: Keep showing you the same papers as you browse (consistent but potentially outdated)&lt;/li&gt;
&lt;li&gt;Option 2: Constantly update with new editions (fresh but confusing)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google typically chooses consistency within a search session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost vs. Coverage
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Buffet Restaurant Analogy&lt;/strong&gt;: &lt;br&gt;
A buffet could offer every dish in the world, but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It would cost millions to maintain&lt;/li&gt;
&lt;li&gt;99% of food would go to waste&lt;/li&gt;
&lt;li&gt;Most people just want common dishes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similarly, Google limits deep pagination because the cost doesn't justify the rare usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Implications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What This Means for Users
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The first few pages matter most&lt;/strong&gt;: Google puts maximum effort into getting these right&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep diving has limits&lt;/strong&gt;: You can't browse all 2 million results—and honestly, you wouldn't want to&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freshness varies&lt;/strong&gt;: Breaking news might not show up if you're on page 10 of yesterday's search&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What Other Sites Learn from Google
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Small Restaurant Principle&lt;/strong&gt;: &lt;br&gt;
Your local restaurant doesn't need a 50-page menu. Similarly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most sites don't need to paginate through millions of results&lt;/li&gt;
&lt;li&gt;Focus on helping users find things quickly on page 1&lt;/li&gt;
&lt;li&gt;Add filters instead of endless pages&lt;/li&gt;
&lt;li&gt;Consider "Load More" buttons instead of page numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Evolution: Mobile and Infinite Scroll
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Escalator vs. Elevator Analogy&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traditional pagination: Like an elevator (discrete floors/pages)&lt;/li&gt;
&lt;li&gt;Infinite scroll: Like an escalator (continuous movement)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mobile Google often uses infinite scroll because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thumb-scrolling is easier than clicking tiny page numbers&lt;/li&gt;
&lt;li&gt;It loads results as needed, saving bandwidth&lt;/li&gt;
&lt;li&gt;Users feel like they're making progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Google's pagination is like a master chef preparing a meal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They could show you every possible dish (all results)&lt;/li&gt;
&lt;li&gt;But they know you can only eat so much (cognitive limits)&lt;/li&gt;
&lt;li&gt;So they carefully prepare the best dishes first (top results)&lt;/li&gt;
&lt;li&gt;And limit the menu size (pagination limits)&lt;/li&gt;
&lt;li&gt;While keeping everything fresh and fast (performance)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The genius isn't in showing you everything—it's in showing you just enough, just in time, without overwhelming you or their servers. It's a delicate balance of user experience, technical constraints, and business efficiency that Google has refined over decades.&lt;/p&gt;

&lt;p&gt;Next time you click "Next page" on Google, remember: you're not just moving through a list. You're experiencing one of the most sophisticated distributed computing systems ever built, disguised as a simple button.&lt;/p&gt;

</description>
      <category>pagination</category>
      <category>systemdesign</category>
      <category>hiddencomplexities</category>
      <category>searchengine</category>
    </item>
    <item>
      <title>Building Scalable Authentication: The Smart Way to Handle Tokens with Redis and Database Storage</title>
      <dc:creator>HarmanPreet-Singh-XYT</dc:creator>
      <pubDate>Mon, 28 Jul 2025 16:10:58 +0000</pubDate>
      <link>https://forem.com/harmanpreetsingh/building-scalable-authentication-the-smart-way-to-handle-tokens-with-redis-and-database-storage-1lcf</link>
      <guid>https://forem.com/harmanpreetsingh/building-scalable-authentication-the-smart-way-to-handle-tokens-with-redis-and-database-storage-1lcf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: Why Traditional Authentication Falls Short
&lt;/h2&gt;

&lt;p&gt;Imagine you're at a high-security office building. Every time you want to enter a room, you need to show your ID to the security desk, wait for them to verify it against their records, and then get permission. Now imagine doing this hundreds of times per day, with thousands of other employees doing the same. The security desk would be overwhelmed, and everyone would waste time waiting.&lt;/p&gt;

&lt;p&gt;This is exactly what happens when we rely solely on database-driven authentication in modern applications. Every API request needs verification, and if each verification hits the database, we create a massive bottleneck. Today, let's explore how combining JWT tokens, Redis, and strategic database usage can solve this problem elegantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two-Token System: Your Digital Security Badge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Understanding Access and Refresh Tokens
&lt;/h3&gt;

&lt;p&gt;Think of the two-token system like having both a daily visitor badge and a master keycard:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access Token (The Daily Badge):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Short-lived (typically 15-30 minutes)&lt;/li&gt;
&lt;li&gt;Used for every API request&lt;/li&gt;
&lt;li&gt;Contains user permissions and basic info&lt;/li&gt;
&lt;li&gt;Like a temporary pass that expires quickly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Refresh Token (The Master Keycard):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long-lived (days or weeks)&lt;/li&gt;
&lt;li&gt;Used only to get new access tokens&lt;/li&gt;
&lt;li&gt;More secure, stored carefully&lt;/li&gt;
&lt;li&gt;Like your employee ID that you use to get new daily badges&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Architecture: Redis + Database Hybrid Approach
&lt;/h2&gt;

&lt;h3&gt;
  
  
  System Design Overview
&lt;/h3&gt;

&lt;p&gt;Our authentication system works like a well-organized office building with multiple security checkpoints:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frontend Security Desk (Client Application)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Holds both tokens&lt;/li&gt;
&lt;li&gt;Presents access token for every request&lt;/li&gt;
&lt;li&gt;Uses refresh token only when access token expires&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fast-Check Station (Redis Cache)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validates access tokens quickly&lt;/li&gt;
&lt;li&gt;Maintains active session information&lt;/li&gt;
&lt;li&gt;Acts like a digital bouncer with a guest list&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Main Security Office (Database)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stores refresh tokens securely&lt;/li&gt;
&lt;li&gt;Handles long-term user data&lt;/li&gt;
&lt;li&gt;Processes token renewal requests&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Authentication Flow
&lt;/h3&gt;

&lt;p&gt;Let me walk you through the process like a story:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initial Login - Getting Your Badges:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User provides credentials (username/password)&lt;/li&gt;
&lt;li&gt;System verifies against database (the slow but necessary check)&lt;/li&gt;
&lt;li&gt;System generates both tokens&lt;/li&gt;
&lt;li&gt;Access token info goes to Redis (the fast-access list)&lt;/li&gt;
&lt;li&gt;Refresh token goes to database (the secure vault)&lt;/li&gt;
&lt;li&gt;Both tokens sent to user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Making Requests - Using Your Daily Badge:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User sends request with access token&lt;/li&gt;
&lt;li&gt;System checks Redis (lightning fast)&lt;/li&gt;
&lt;li&gt;If valid, request proceeds&lt;/li&gt;
&lt;li&gt;If invalid/expired, rejection with "token expired" message&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Token Refresh - Getting a New Daily Badge:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User sends refresh token to renewal endpoint&lt;/li&gt;
&lt;li&gt;System checks database for refresh token validity&lt;/li&gt;
&lt;li&gt;If valid, generates new access token&lt;/li&gt;
&lt;li&gt;Updates Redis with new access token info&lt;/li&gt;
&lt;li&gt;Sends new access token to user&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Benefits: Why This Design Shines
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Drastically Reduced Database Load
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Traditional Approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1000 users × 100 requests/day = 100,000 database hits&lt;/li&gt;
&lt;li&gt;Each hit takes ~50ms = 5,000 seconds of database time daily&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Redis Hybrid Approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access token checks: 100,000 Redis hits (&amp;lt; 1ms each)&lt;/li&gt;
&lt;li&gt;Refresh token checks: ~3,000 database hits (assuming 30-min tokens)&lt;/li&gt;
&lt;li&gt;Total database time: ~150 seconds (97% reduction!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Blazing Fast Performance
&lt;/h3&gt;

&lt;p&gt;Redis operates in-memory, making token validation almost instantaneous. It's like the difference between checking a list on your phone versus driving to the library to look it up in a book.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Enhanced Security Through Isolation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Compromised access tokens expire quickly&lt;/li&gt;
&lt;li&gt;Refresh tokens are accessed rarely, reducing exposure&lt;/li&gt;
&lt;li&gt;Each token serves a specific purpose, following the principle of least privilege&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Scalability Built-In
&lt;/h3&gt;

&lt;p&gt;As your user base grows, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add more Redis instances (horizontal scaling)&lt;/li&gt;
&lt;li&gt;Keep the database focused on critical operations&lt;/li&gt;
&lt;li&gt;Handle millions of validations without breaking a sweat&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Challenges: Honest Discussion of Drawbacks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Increased Complexity
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Reality:&lt;/strong&gt; You're now managing two storage systems instead of one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mitigation:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use established patterns and libraries&lt;/li&gt;
&lt;li&gt;Document the flow clearly&lt;/li&gt;
&lt;li&gt;Implement comprehensive monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Redis Dependency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Risk:&lt;/strong&gt; If Redis goes down, authentication fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solutions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement Redis clustering for high availability&lt;/li&gt;
&lt;li&gt;Have a fallback mechanism to database (with rate limiting)&lt;/li&gt;
&lt;li&gt;Use Redis persistence features for quick recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Token Synchronization Issues
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Challenge:&lt;/strong&gt; Ensuring Redis and database stay in sync.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement proper TTL (Time To Live) in Redis&lt;/li&gt;
&lt;li&gt;Use event-driven updates when tokens are revoked&lt;/li&gt;
&lt;li&gt;Regular cleanup jobs for orphaned entries&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Storage Overhead
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Cost:&lt;/strong&gt; Storing session data in two places.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimization:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store minimal data in Redis (user ID, permissions, expiry)&lt;/li&gt;
&lt;li&gt;Use Redis memory optimization techniques&lt;/li&gt;
&lt;li&gt;Implement intelligent cache eviction policies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Scenarios and Outcomes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1: E-Commerce Platform During Flash Sale
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Without Redis:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database overwhelmed with authentication queries&lt;/li&gt;
&lt;li&gt;Legitimate users face timeouts&lt;/li&gt;
&lt;li&gt;Lost sales due to poor performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;With Redis:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication remains snappy&lt;/li&gt;
&lt;li&gt;Database focuses on order processing&lt;/li&gt;
&lt;li&gt;Happy customers, successful sale&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scenario 2: Social Media App with Sudden Viral Content
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Situation:&lt;/strong&gt; A post goes viral, bringing 10x normal traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result with Redis Architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication layer handles the spike effortlessly&lt;/li&gt;
&lt;li&gt;Users experience no login delays&lt;/li&gt;
&lt;li&gt;System administrators sleep peacefully&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scenario 3: Financial Services App
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Security Requirement:&lt;/strong&gt; Immediate token revocation for compromised accounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove access token from Redis → Instant block&lt;/li&gt;
&lt;li&gt;Invalidate refresh token in database → Permanent revocation&lt;/li&gt;
&lt;li&gt;User forced to re-authenticate → Security restored&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices for Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Token Lifecycle Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access Tokens:&lt;/strong&gt; 15-30 minutes (balance between security and UX)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refresh Tokens:&lt;/strong&gt; 7-30 days (based on security requirements)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis TTL:&lt;/strong&gt; Match access token expiry + small buffer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Security Considerations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Encrypt sensitive data in tokens&lt;/li&gt;
&lt;li&gt;Use secure random generators for token creation&lt;/li&gt;
&lt;li&gt;Implement refresh token rotation for extra security&lt;/li&gt;
&lt;li&gt;Monitor for unusual refresh patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Performance Optimization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Batch Redis operations where possible&lt;/li&gt;
&lt;li&gt;Use Redis pipelining for multiple checks&lt;/li&gt;
&lt;li&gt;Implement connection pooling&lt;/li&gt;
&lt;li&gt;Monitor Redis memory usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Error Handling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Graceful fallbacks for Redis failures&lt;/li&gt;
&lt;li&gt;Clear error messages for token issues&lt;/li&gt;
&lt;li&gt;Automatic retry mechanisms with exponential backoff&lt;/li&gt;
&lt;li&gt;Comprehensive logging for debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monitoring and Maintenance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Key Metrics to Track
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Redis Performance:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hit/miss ratio&lt;/li&gt;
&lt;li&gt;Response times&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;Connection pool health&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Token Usage:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refresh frequency&lt;/li&gt;
&lt;li&gt;Token expiry patterns&lt;/li&gt;
&lt;li&gt;Failed authentication attempts&lt;/li&gt;
&lt;li&gt;Unusual access patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;System Health:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database query times&lt;/li&gt;
&lt;li&gt;Redis availability&lt;/li&gt;
&lt;li&gt;Error rates&lt;/li&gt;
&lt;li&gt;User experience metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion: The Path Forward
&lt;/h2&gt;

&lt;p&gt;Implementing a Redis-backed authentication system with separate access and refresh tokens isn't just a technical optimization—it's a fundamental architectural decision that pays dividends as your application scales.&lt;/p&gt;

&lt;p&gt;The beauty of this approach lies in its elegance: frequently accessed data lives in fast storage, while sensitive, rarely-accessed data remains in secure, persistent storage. It's like organizing your home where everyday items are within arm's reach, while valuable documents stay in a safe.&lt;/p&gt;

&lt;p&gt;As developers, we often face the trade-off between complexity and performance. This authentication pattern represents one of those rare cases where a modest increase in complexity yields exponential benefits in performance, security, and scalability.&lt;/p&gt;

&lt;p&gt;Whether you're building the next social media giant or a modest SaaS application, implementing this pattern early will save you from painful refactoring later. Your future self (and your users) will thank you when your authentication system handles that unexpected viral moment with grace.&lt;/p&gt;

&lt;p&gt;Remember: great authentication is invisible to users but robust for developers. This architecture achieves both, making it a powerful tool in your system design arsenal.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>sessionswithredis</category>
      <category>tokenbasedauthentication</category>
      <category>jwt</category>
    </item>
  </channel>
</rss>
