<?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: Nevin-Bali100</title>
    <description>The latest articles on DEV Community by Nevin-Bali100 (@nevin100).</description>
    <link>https://dev.to/nevin100</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%2F1919147%2F30712a4e-f46d-449f-9778-53e2ab8dec69.jpg</url>
      <title>DEV Community: Nevin-Bali100</title>
      <link>https://dev.to/nevin100</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nevin100"/>
    <language>en</language>
    <item>
      <title>Building DevDocAI — A Production Multi-Agent LangGraph System | Part 6 — The Full Loop Works. Now: Deployment...</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Fri, 11 Sep 2026 06:22:31 +0000</pubDate>
      <link>https://dev.to/nevin100/building-devdocai-part-6-the-full-loop-works-now-deployment-3a49</link>
      <guid>https://dev.to/nevin100/building-devdocai-part-6-the-full-loop-works-now-deployment-3a49</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series:&lt;/strong&gt; Building DevDocAI — A Production Multi-Agent LangGraph System&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 6&lt;/strong&gt; — The Full Loop Works. Now: Deployment.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpir2wdhlwj65f8ov7fz5.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%2Fpir2wdhlwj65f8ov7fz5.png" alt="landing Page" width="799" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Milestone
&lt;/h2&gt;

&lt;p&gt;Something clicked this week that hasn't clicked before in this project.&lt;/p&gt;

&lt;p&gt;I connected a real GitHub repo through the dashboard, watched the pipeline parse it, generate docs with an LLM, enrich them with external context, pause for my review, got the "Docs approved" screen after clicking approve, and then asked the onboarding chatbot a question about that exact repo — and got a real, grounded answer back.&lt;/p&gt;

&lt;p&gt;Not a demo. Not a curl command against an endpoint. A real browser, a real GitHub account, five agents, two databases, and a vector store, all talking to each other correctly.&lt;/p&gt;

&lt;p&gt;That's the milestone. Here's everything that had to get fixed to get there — because it wasn't one clean run.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqx7hi4v1aorckwm6fl44.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%2Fqx7hi4v1aorckwm6fl44.png" alt="Dashboard" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Debugging Gauntlet
&lt;/h2&gt;

&lt;p&gt;I'm not going to pretend this was smooth. Getting from "the pipeline runs once" to "the pipeline runs reliably, every time, from a cold start" surfaced a string of production-grade bugs, each one small but each one a real lesson.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The checkpointer connection kept dying
&lt;/h3&gt;

&lt;p&gt;The first version of the LangGraph PostgreSQL checkpointer opened a single raw connection and held onto it. Neon — being serverless — closes idle connections after a while. The second time I ran the pipeline, everything blew up with &lt;code&gt;the connection is closed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The fix was switching to a proper connection pool:&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;_pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AsyncConnectionPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;conninfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;psycopg_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_size&lt;/span&gt;&lt;span class="o"&gt;=&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;kwargs&lt;/span&gt;&lt;span class="o"&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;autocommit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;_checkpointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AsyncPostgresSaver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A pool self-heals. A single connection doesn't. That's the whole lesson, but it cost a few hours to land on.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. &lt;code&gt;aupdate_state&lt;/code&gt;, not &lt;code&gt;update_state&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The HITL resume endpoint calls &lt;code&gt;doc_graph.update_state(...)&lt;/code&gt; to inject the human's decision back into a paused graph. Except with an &lt;em&gt;async&lt;/em&gt; checkpointer, that call has to be awaited and it has to be the async variant:&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="c1"&gt;# silently broken
&lt;/span&gt;&lt;span class="n"&gt;doc_graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt; &lt;span class="n"&gt;as_node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;human_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# correct
&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;doc_graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aupdate_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt; &lt;span class="n"&gt;as_node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;human_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The sync version doesn't error loudly with an async backend — it just doesn't behave. Easy to miss, annoying to trace.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Cohere → HuggingFace, mid-project
&lt;/h3&gt;

&lt;p&gt;Embeddings were originally wired to Cohere. When the API key turned out to be invalid and I didn't want another external dependency with rate limits, I swapped to local &lt;code&gt;sentence-transformers&lt;/code&gt; embeddings — completely free, runs on-device, no network call:&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;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HuggingFaceEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_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;sentence-transformers/all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The catch: Cohere's model outputs 1024-dimension vectors, MiniLM outputs 384. Qdrant collections are locked to a vector size at creation time. Every "vector dimension error: expected 1024, got 384" was the collection remembering the old model. The collection had to be deleted and recreated once the embedding model changed — not something obvious until you hit it.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Qdrant Cloud wants an explicit index
&lt;/h3&gt;

&lt;p&gt;Filtering search results by &lt;code&gt;repo_id&lt;/code&gt; worked fine on paper, then Qdrant Cloud rejected it:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Index required but not found for "repo_id" of type: [keyword]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Local Qdrant setups can be more lenient; the managed cloud version requires you to explicitly create a payload index before you can filter on a field:&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;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_payload_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;collection_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QDRANT_COLLECTION_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;field_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;repo_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;field_schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PayloadSchemaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEYWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now baked into the same startup routine that creates the collection, so it never has to be a manual step again.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Brave Search killed its free tier mid-build
&lt;/h3&gt;

&lt;p&gt;Genuinely — while building this, Brave Search API dropped its card-free 2,000 queries/month plan in favor of a credit-card-required $5-monthly-credit model. Rather than add a billing dependency to a side project, I swapped the research agent over to Tavily, which still has a genuinely free, card-free tier and is built specifically for agent/RAG use cases. Same node, same interface, different provider underneath — this is exactly why the agent is isolated behind one function boundary in the graph.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why None of This Broke the Architecture
&lt;/h2&gt;

&lt;p&gt;Every one of these was a &lt;em&gt;plumbing&lt;/em&gt; fix — a connection strategy, an await keyword, a vector dimension, an index, a provider swap. Not one of them touched the graph structure, the agent responsibilities, or the API contracts the frontend depends on.&lt;/p&gt;

&lt;p&gt;That's not an accident. It's the payoff of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One node per responsibility&lt;/strong&gt; — swapping Brave for Tavily meant editing one file, not touching the graph definition&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A repository layer&lt;/strong&gt; — the DB never leaked SQL into the pipeline logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single embeddings module&lt;/strong&gt; — changing providers meant editing one file, &lt;code&gt;vectorstore/embeddings.py&lt;/code&gt;, and nothing that calls it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The infrastructure decisions from Part 1 kept paying rent, four months later.&lt;/p&gt;


&lt;h2&gt;
  
  
  Also Fixed This Round
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RAG counting questions&lt;/strong&gt; — the chatbot was confidently answering "how many modules are in this repo?" using only its top-4 retrieved chunks, not the whole repo. Fixed with a stricter system prompt that forces the model to say "here's what I can confirm from what I retrieved" instead of presenting a partial view as a total, plus raising &lt;code&gt;top_k&lt;/code&gt; from 4 to 15 for broader coverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown rendering in chat&lt;/strong&gt; — responses were coming back with literal &lt;code&gt;**bold**&lt;/code&gt; and table pipes instead of rendered formatting. Added &lt;code&gt;react-markdown&lt;/code&gt; + &lt;code&gt;remark-gfm&lt;/code&gt; to the chat bubble.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A polished HITL review UI&lt;/strong&gt; — proper loading/error/empty/done states, a full-screen pipeline loader with staged progress instead of a blank screen during the multi-minute run, hover states and skeleton loaders across the dashboard.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Where Things Stand
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend (13 endpoints)&lt;/td&gt;
&lt;td&gt;✅ Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-agent pipeline, end-to-end&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;Confirmed working live&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub OAuth&lt;/td&gt;
&lt;td&gt;✅ Working&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard, review, chat — wired to real data&lt;/td&gt;
&lt;td&gt;✅ Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAG chatbot honesty/accuracy&lt;/td&gt;
&lt;td&gt;✅ Improved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phase 7 — Docker, ECR, ECS Fargate, CI/CD&lt;/td&gt;
&lt;td&gt;🔨 &lt;strong&gt;Starting now&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is genuinely the last major checkpoint before deployment. Everything from here is Dockerfiles, a docker-compose setup for local full-stack testing, GitHub Actions for build-and-push, and getting this running on AWS instead of my laptop.&lt;/p&gt;


&lt;h2&gt;
  
  
  What's Next — Part 7
&lt;/h2&gt;

&lt;p&gt;Phase 7. Containerizing the backend and frontend, pushing images to ECR, standing up ECS Fargate services, and wiring a CI/CD pipeline so a merge to main ships to production without me touching a terminal.&lt;/p&gt;

&lt;p&gt;This is also where the "dev environment held together with local Docker and Neon" setup meets real infrastructure decisions — VPCs, security groups, environment secrets, the works.&lt;/p&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flp7lnhnx2oghkyitgzic.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%2Flp7lnhnx2oghkyitgzic.png" alt=" " width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Nevin100" rel="noopener noreferrer"&gt;
        Nevin100
      &lt;/a&gt; / &lt;a href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;
        DevdocxAI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DevDocxAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates engineering documentation by deeply understanding you…DevDocAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates doc. by understanding deeply.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DevDocxAI 🤖📄&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;DevDocxAi is a production-grade multi-agent LangGraph system that automatically generates and updates engineering documentation from your GitHub codebase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e"&gt;&lt;img src="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e" alt="Python"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069"&gt;&lt;img src="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265" alt="LangGraph"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c"&gt;&lt;img src="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c" alt="PostgreSQL"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265" alt="Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚨 The Problem:&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Every engineering team has the same dirty secret — &lt;strong&gt;the docs are lying.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not intentionally. Code moves fast, documentation doesn't.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New dev joins → 2 weeks reading outdated wikis&lt;/li&gt;
&lt;li&gt;Senior engineers constantly interrupted with "what does this do?"&lt;/li&gt;
&lt;li&gt;PR gets merged → docs never updated&lt;/li&gt;
&lt;li&gt;Generic RAG chatbots don't understand code &lt;em&gt;structure&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DevDocAI fixes this.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ What It Does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Connects to your GitHub repo&lt;/strong&gt; via OAuth&lt;/li&gt;
&lt;li&gt;🌳 &lt;strong&gt;Parses your codebase at the AST level&lt;/strong&gt; — understands functions, classes, modules&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Auto-generates structured documentation&lt;/strong&gt; per module and function&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Updates docs on every PR merge&lt;/strong&gt; via GitHub webhooks&lt;/li&gt;
&lt;li&gt;👀 &lt;strong&gt;Human-in-the-Loop review&lt;/strong&gt; — you approve before anything goes live&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Onboarding chatbot&lt;/strong&gt; — new devs ask questions, get answers from live code&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤖 Agent Pipeline&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;START
  ↓
codebase_parser&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;&lt;em&gt;Building in public — from "it ran once" to "it's about to run in production."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;python&lt;/code&gt; &lt;code&gt;langgraph&lt;/code&gt; &lt;code&gt;fastapi&lt;/code&gt; &lt;code&gt;qdrant&lt;/code&gt; &lt;code&gt;rag&lt;/code&gt; &lt;code&gt;docker&lt;/code&gt; &lt;code&gt;aws&lt;/code&gt; &lt;code&gt;opensource&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>langchain</category>
      <category>python</category>
      <category>rag</category>
      <category>langsmith</category>
    </item>
    <item>
      <title>Building DevDocAI — A Production Multi-Agent LangGraph System | Part 5 - Backend Closed Out, GitHub OAuth Working End-to-End</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Sat, 29 Aug 2026 14:52:50 +0000</pubDate>
      <link>https://dev.to/nevin100/building-devdocai-a-production-multi-agent-langgraph-system-part-5-backend-closed-out-github-216o</link>
      <guid>https://dev.to/nevin100/building-devdocai-a-production-multi-agent-langgraph-system-part-5-backend-closed-out-github-216o</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series:&lt;/strong&gt; Building DevDocAI — A Production Multi-Agent LangGraph System&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 5&lt;/strong&gt; — Backend Closed Out, GitHub OAuth Working End-to-End&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Quick Update
&lt;/h2&gt;

&lt;p&gt;Short post this time — but a meaningful checkpoint.&lt;/p&gt;

&lt;p&gt;Since Part 4, two things happened:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The backend is now &lt;strong&gt;fully complete&lt;/strong&gt; — all 13 endpoints, tested and working.&lt;/li&gt;
&lt;li&gt;GitHub OAuth is wired &lt;strong&gt;frontend → backend → GitHub → back again&lt;/strong&gt;, and I watched it work end-to-end for the first time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That second one felt bigger than it sounds. Let me walk through both.&lt;/p&gt;




&lt;h2&gt;
  
  
  Backend — The Final Two Endpoints
&lt;/h2&gt;

&lt;p&gt;Part 4 left two gaps: no way to browse a user's actual GitHub repos, and no way to trigger the pipeline outside of a PR merge webhook. Both are closed now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;GET /github/repos&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Pulls the user's repos directly from GitHub — not from our DB. New MCP tool, &lt;code&gt;list_user_repos&lt;/code&gt;, wraps &lt;code&gt;PyGithub&lt;/code&gt;'s &lt;code&gt;user.get_repos()&lt;/code&gt; and returns the fields the frontend actually needs: name, default branch, visibility, language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;POST /repos/{repo_id}/run&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
The manual trigger. Connect a repo → hit this → the full LangGraph pipeline starts immediately instead of waiting for a PR to merge. Same &lt;code&gt;run_pipeline()&lt;/code&gt; the webhook uses, just a different entry point and &lt;code&gt;trigger="manual"&lt;/code&gt; instead of &lt;code&gt;"pr_merge"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Full endpoint list now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST  /auth/register
POST  /auth/login
GET   /auth/github
POST  /auth/github/callback
GET   /auth/me
POST  /webhooks/github
GET   /repos
GET   /github/repos
POST  /repos/connect
POST  /repos/{repo_id}/run
GET   /pipeline/{thread_id}/state
POST  /pipeline/review
POST  /chat/ask
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Backend's done. Every agent, every checkpoint, every route the frontend needs — all there.&lt;/p&gt;


&lt;h2&gt;
  
  
  GitHub OAuth — Where It Actually Broke
&lt;/h2&gt;

&lt;p&gt;This is the part worth writing down, because the bug was sneaky.&lt;/p&gt;

&lt;p&gt;The flow is: frontend asks the backend for a GitHub authorize URL, backend builds it using &lt;code&gt;GITHUB_REDIRECT_URI&lt;/code&gt; from &lt;code&gt;.env&lt;/code&gt;, GitHub redirects back to that exact URI with a &lt;code&gt;code&lt;/code&gt;, frontend catches it and exchanges it for a session.&lt;/p&gt;

&lt;p&gt;I updated &lt;code&gt;GITHUB_REDIRECT_URI&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; from the backend's own callback route to the frontend's:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# before
&lt;/span&gt;&lt;span class="n"&gt;GITHUB_REDIRECT_URI&lt;/span&gt;=&lt;span class="n"&gt;http&lt;/span&gt;://&lt;span class="n"&gt;localhost&lt;/span&gt;:&lt;span class="m"&gt;8000&lt;/span&gt;/&lt;span class="n"&gt;auth&lt;/span&gt;/&lt;span class="n"&gt;github&lt;/span&gt;/&lt;span class="n"&gt;callback&lt;/span&gt;

&lt;span class="c"&gt;# after
&lt;/span&gt;&lt;span class="n"&gt;GITHUB_REDIRECT_URI&lt;/span&gt;=&lt;span class="n"&gt;http&lt;/span&gt;://&lt;span class="n"&gt;localhost&lt;/span&gt;:&lt;span class="m"&gt;3000&lt;/span&gt;/&lt;span class="n"&gt;auth&lt;/span&gt;/&lt;span class="n"&gt;callback&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Updated the GitHub OAuth App's redirect URI to match. Tested without restarting the server. GitHub threw:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Be careful!&lt;/strong&gt; The &lt;code&gt;redirect_uri&lt;/code&gt; is not associated with this application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The URL in the browser still showed &lt;code&gt;localhost:8000&lt;/code&gt;. &lt;code&gt;.env&lt;/code&gt; was correct. GitHub App settings were correct. So why was the old value still being used?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;@lru_cache()&lt;/code&gt; on &lt;code&gt;get_settings()&lt;/code&gt;.&lt;/strong&gt; The settings object gets built once and cached for the life of the process — editing &lt;code&gt;.env&lt;/code&gt; while the server is still running (even with &lt;code&gt;--reload&lt;/code&gt;, which only watches code files, not env vars) does nothing. A full stop and restart was needed to actually rebuild the cached &lt;code&gt;Settings&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;Small gotcha, easy fix, but worth remembering: &lt;strong&gt;env var changes need a hard restart, not a hot reload.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Seeing It Work
&lt;/h2&gt;

&lt;p&gt;After the restart, the full loop:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/login → "Continue with GitHub"
      → GitHub authorize screen
      → redirects to localhost:3000/auth/callback?code=xxx
      → frontend exchanges code with backend
      → JWT stored
      → /dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And it just worked. Landed on the dashboard, GitHub username in the top corner, no errors in either console.&lt;/p&gt;

&lt;p&gt;There's something different about a full auth loop working versus a single endpoint returning &lt;code&gt;200&lt;/code&gt; in Swagger. This is the first time a real browser, a real GitHub account, and the actual frontend all talked to each other correctly. It's the first "this feels like a product" moment in the project.&lt;/p&gt;


&lt;h2&gt;
  
  
  Where Things Stand
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend (13 endpoints)&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub OAuth, frontend to backend&lt;/td&gt;
&lt;td&gt;Working, tested live&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend pages (landing, auth, dashboard, review, chat)&lt;/td&gt;
&lt;td&gt;Built&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard / review / chat wired to real data&lt;/td&gt;
&lt;td&gt;Next&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phase 7 — Docker, ECR, ECS, CI/CD&lt;/td&gt;
&lt;td&gt;Untouched&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The dashboard is currently rendering against sample repos. Next step is swapping that for &lt;code&gt;GET /repos&lt;/code&gt; and &lt;code&gt;GET /github/repos&lt;/code&gt;, and making "Connect repository" actually call &lt;code&gt;POST /repos/connect&lt;/code&gt; followed by &lt;code&gt;POST /repos/{id}/run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's Part 6.&lt;/p&gt;


&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Nevin100" rel="noopener noreferrer"&gt;
        Nevin100
      &lt;/a&gt; / &lt;a href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;
        DevdocxAI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DevDocxAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates engineering documentation by deeply understanding you…DevDocAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates doc. by understanding deeply.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DevDocxAI 🤖📄&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;DevDocxAi is a production-grade multi-agent LangGraph system that automatically generates and updates engineering documentation from your GitHub codebase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e"&gt;&lt;img src="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e" alt="Python"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069"&gt;&lt;img src="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265" alt="LangGraph"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c"&gt;&lt;img src="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c" alt="PostgreSQL"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265" alt="Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚨 The Problem:&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Every engineering team has the same dirty secret — &lt;strong&gt;the docs are lying.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not intentionally. Code moves fast, documentation doesn't.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New dev joins → 2 weeks reading outdated wikis&lt;/li&gt;
&lt;li&gt;Senior engineers constantly interrupted with "what does this do?"&lt;/li&gt;
&lt;li&gt;PR gets merged → docs never updated&lt;/li&gt;
&lt;li&gt;Generic RAG chatbots don't understand code &lt;em&gt;structure&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DevDocAI fixes this.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ What It Does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Connects to your GitHub repo&lt;/strong&gt; via OAuth&lt;/li&gt;
&lt;li&gt;🌳 &lt;strong&gt;Parses your codebase at the AST level&lt;/strong&gt; — understands functions, classes, modules&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Auto-generates structured documentation&lt;/strong&gt; per module and function&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Updates docs on every PR merge&lt;/strong&gt; via GitHub webhooks&lt;/li&gt;
&lt;li&gt;👀 &lt;strong&gt;Human-in-the-Loop review&lt;/strong&gt; — you approve before anything goes live&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Onboarding chatbot&lt;/strong&gt; — new devs ask questions, get answers from live code&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤖 Agent Pipeline&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;START
  ↓
codebase_parser&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;&lt;em&gt;Building in public — one working loop at a time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;python&lt;/code&gt; &lt;code&gt;nextjs&lt;/code&gt; &lt;code&gt;oauth&lt;/code&gt; &lt;code&gt;fastapi&lt;/code&gt; &lt;code&gt;langgraph&lt;/code&gt; &lt;code&gt;webdev&lt;/code&gt; &lt;code&gt;opensource&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>langchain</category>
      <category>fastapi</category>
      <category>git</category>
    </item>
    <item>
      <title>Building DevDocAI — A Production Multi-Agent LangGraph System | Part 4 — Coming Back, Closing Out the Backend, and Laying Down the Frontend</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Thu, 27 Aug 2026 13:29:56 +0000</pubDate>
      <link>https://dev.to/nevin100/building-devdocai-a-production-multi-agent-langgraph-system-part-4-coming-back-closing-out-5aa9</link>
      <guid>https://dev.to/nevin100/building-devdocai-a-production-multi-agent-langgraph-system-part-4-coming-back-closing-out-5aa9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series:&lt;/strong&gt; Building DevDocAI — A Production Multi-Agent LangGraph System&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 4&lt;/strong&gt; — Coming Back, Closing Out the Backend, and Laying Down the Frontend&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqvdi9sl3xov2ttuxq5em.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%2Fqvdi9sl3xov2ttuxq5em.png" alt="code-editor-image" width="799" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I Disappeared To
&lt;/h2&gt;

&lt;p&gt;It's been about a month since Part 3.&lt;/p&gt;

&lt;p&gt;No sugarcoating it — health took a hit, and along with a few other things piling up, DevDocAI sat untouched for weeks. Not proud of the silence, but I'd rather be honest about it than pretend the "building in public" streak was unbroken.&lt;/p&gt;

&lt;p&gt;Here's the thing though — the project didn't die. It waited.&lt;/p&gt;

&lt;p&gt;And this week I sat back down, opened the repo, and picked up exactly where I left off. No rewrite, no "let me restart with a cleaner approach" spiral. Just continuing.&lt;/p&gt;

&lt;p&gt;If you're building something and life knocks you off pace — the comeback matters more than the streak. This post is that comeback.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap — Where Things Stood
&lt;/h2&gt;

&lt;p&gt;By the end of Part 3, DevDocAI had:&lt;/p&gt;

&lt;p&gt;✅ Full multi-agent LangGraph pipeline (parser → generator → researcher → HITL → publisher)&lt;br&gt;&lt;br&gt;
✅ GitHub OAuth + encrypted token storage&lt;br&gt;&lt;br&gt;
✅ GitHub PR webhook auto-triggering the pipeline&lt;br&gt;&lt;br&gt;
✅ Redis caching layer&lt;br&gt;&lt;br&gt;
✅ Qdrant + Cohere RAG for the onboarding chatbot  &lt;/p&gt;

&lt;p&gt;The backend was functionally complete for the pipeline itself. But the &lt;em&gt;surface area&lt;/em&gt; a frontend would actually need to talk to — repos, pipeline state, chat — wasn't there yet.&lt;/p&gt;

&lt;p&gt;That's what this phase closes out.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 1 — Finishing the Backend
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Neon Detour
&lt;/h3&gt;

&lt;p&gt;Small but real lesson here: I'd been running Postgres locally in Docker, forgot the password mid-project (it happens), and instead of fighting a container password reset for the fourth time, I just switched dev to &lt;strong&gt;Neon&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# before — local docker, constant password drama
DATABASE_URL=postgresql+asyncpg://postgres:???@localhost:5432/devdocai

# after — one connection string, zero local state to babysit
DATABASE_URL=postgresql+asyncpg://neondb_owner:***@ep-xxxx.neon.tech/neondb?ssl=require
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Two gotchas worth flagging for anyone hitting the same wall:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Neon gives you &lt;code&gt;postgresql://&lt;/code&gt; — you have to manually add &lt;code&gt;+asyncpg&lt;/code&gt; for SQLAlchemy's async engine&lt;/li&gt;
&lt;li&gt;Neon's copied connection string uses &lt;code&gt;sslmode=require&amp;amp;channel_binding=require&lt;/code&gt;, but &lt;code&gt;asyncpg&lt;/code&gt; only understands &lt;code&gt;ssl=require&lt;/code&gt;. Drop the rest or the connection just silently fails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once that was sorted, all four tables (&lt;code&gt;users&lt;/code&gt;, &lt;code&gt;repositories&lt;/code&gt;, &lt;code&gt;documents&lt;/code&gt;, &lt;code&gt;pipeline_runs&lt;/code&gt;) created cleanly against Neon and stayed that way.&lt;/p&gt;
&lt;h3&gt;
  
  
  Three Endpoints That Were Missing
&lt;/h3&gt;

&lt;p&gt;The pipeline could run end-to-end via webhook, but nothing existed to let a frontend &lt;em&gt;see into&lt;/em&gt; it. So I added:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;GET /repos&lt;/code&gt; + &lt;code&gt;POST /repos/connect&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Lets a user list their connected repos and register a new one against their account. Standard repository-pattern CRUD — route stays thin, &lt;code&gt;RepoService&lt;/code&gt; holds the logic, &lt;code&gt;RepoRepository&lt;/code&gt; owns the queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;GET /pipeline/{thread_id}/state&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
This one's the interesting one. It doesn't touch a custom table — it reads straight from the LangGraph PostgreSQL checkpointer:&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;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;doc_graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aget_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Whatever state the graph paused at — mid-parse, mid-generation, sitting at &lt;code&gt;human_review&lt;/code&gt; — this endpoint reflects it live. No separate "sync the graph state to a table" step needed. The checkpointer already &lt;em&gt;is&lt;/em&gt; the source of truth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;POST /pipeline/review&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
The HITL resume endpoint. A dev approves or rejects on the frontend, this calls &lt;code&gt;resume_pipeline()&lt;/code&gt;, and the paused graph continues exactly where it left off — either to &lt;code&gt;doc_publisher&lt;/code&gt; or back to &lt;code&gt;doc_generator&lt;/code&gt; with their notes as feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;POST /chat/ask&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Runs the onboarding chatbot graph as a one-shot call. Each question gets its own &lt;code&gt;thread_id&lt;/code&gt; — no need to persist a running conversation for a simple Q&amp;amp;A endpoint like this.&lt;/p&gt;

&lt;p&gt;Backend endpoint count now:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST  /auth/register
POST  /auth/login
GET   /auth/github
POST  /auth/github/callback
GET   /auth/me
POST  /webhooks/github
GET   /repos
POST  /repos/connect
GET   /pipeline/{thread_id}/state
POST  /pipeline/review
POST  /chat/ask
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2 — Laying Down the Frontend
&lt;/h2&gt;

&lt;p&gt;This is genuinely new ground for the series — first time anything visual exists.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Stack
&lt;/h3&gt;

&lt;p&gt;Next.js 15, TypeScript, Tailwind, App Router, &lt;code&gt;src/&lt;/code&gt; directory. Nothing exotic — I wanted the frontend boring and the backend interesting, not the other way around.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Design Direction
&lt;/h3&gt;

&lt;p&gt;Instead of defaulting to "dark theme, blue accent, done," I tied the visual language to the actual product: an ink background (&lt;code&gt;#0b0e14&lt;/code&gt;), and three accent colors mapped directly to what the pipeline stages &lt;em&gt;mean&lt;/em&gt; —&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Teal&lt;/strong&gt; — parsing / published states&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Violet&lt;/strong&gt; — generation / enrichment (the LLM-heavy steps)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amber&lt;/strong&gt; — the human checkpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typography: Space Grotesk for headings, Inter for body, JetBrains Mono for anything code- or pipeline-related.&lt;/p&gt;

&lt;p&gt;The signature piece on the landing page is a small animated component — &lt;code&gt;PipelineStrip&lt;/code&gt; — that cycles through the five actual agent names (&lt;code&gt;codebase_parser → doc_generator → brave_researcher → human_review → doc_publisher&lt;/code&gt;) with the dot lighting up amber right at &lt;code&gt;human_review&lt;/code&gt;. It's not a generic hero animation; it's literally the product's own pipeline, visualized.&lt;/p&gt;
&lt;h3&gt;
  
  
  Pages Built
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;frontend/src/
├── app/
│   ├── page.tsx          ← landing, with the pipeline strip
│   ├── login/page.tsx    ← email/password + GitHub OAuth
│   ├── signup/page.tsx   ← same, register flow
│   ├── dashboard/page.tsx← connected repos, status dots
│   ├── review/page.tsx   ← HITL approve/reject panel
│   └── chat/page.tsx     ← onboarding chatbot UI
├── components/
│   ├── Navbar.tsx
│   └── PipelineStrip.tsx
└── lib/
    └── api.ts            ← typed fetch wrapper for the FastAPI backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Login and signup are &lt;strong&gt;fully wired&lt;/strong&gt; — they hit &lt;code&gt;/auth/register&lt;/code&gt;, &lt;code&gt;/auth/login&lt;/code&gt;, &lt;code&gt;/auth/github&lt;/code&gt; for real and store the JWT. Dashboard, review, and chat are built against the real API client too, but since repo-connect and pipeline flows need an actual end-to-end run to populate them, they're currently rendering against sample data with clearly marked &lt;code&gt;TODO&lt;/code&gt;s pointing at the exact endpoint each one needs.&lt;/p&gt;
&lt;h3&gt;
  
  
  A Tailwind v4 Gotcha
&lt;/h3&gt;

&lt;p&gt;Quick note because it cost some time: newer &lt;code&gt;create-next-app&lt;/code&gt; scaffolds ship &lt;strong&gt;Tailwind v4&lt;/strong&gt; by default, which no longer uses &lt;code&gt;@tailwind base/components/utilities&lt;/code&gt;. It's:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If your custom colors suddenly stop applying and everything renders as unstyled HTML, check your Tailwind major version before anything else.&lt;/p&gt;


&lt;h2&gt;
  
  
  What's Actually Left
&lt;/h2&gt;

&lt;p&gt;Being straight about the gap, not just declaring victory:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend — two small pieces&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /github/repos&lt;/code&gt; — right now &lt;code&gt;/repos&lt;/code&gt; only lists repos already connected in &lt;em&gt;our&lt;/em&gt; DB. There's no endpoint yet to browse the user's actual GitHub repos to connect one for the first time.&lt;/li&gt;
&lt;li&gt;A manual pipeline trigger (&lt;code&gt;POST /repos/{id}/run&lt;/code&gt;) — right now the pipeline only starts from a PR-merge webhook. For a "connect repo → see docs immediately" first-run experience, a manual trigger is needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Frontend — the integration pass&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wiring dashboard/review/chat off sample data and onto the real endpoints above&lt;/li&gt;
&lt;li&gt;Handling the GitHub OAuth redirect callback page&lt;/li&gt;
&lt;li&gt;Loading and empty states for a pipeline that's actually running&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 7 — untouched&lt;/strong&gt;&lt;br&gt;
Docker, ECR, ECS Fargate, GitHub Actions CI/CD. Still ahead.&lt;/p&gt;


&lt;h2&gt;
  
  
  What I'm Taking From the Break
&lt;/h2&gt;

&lt;p&gt;Momentum matters, but it's not the whole story. The month off didn't erase the project — the code was exactly as I left it, the architecture still made sense coming back to it cold, and picking it back up took an afternoon, not a rebuild.&lt;/p&gt;

&lt;p&gt;That's the actual payoff of the layered architecture and the checkpointed graph state I set up back in Part 1 and Part 3: things I built for "production correctness" turned out to also be what made a month-long gap survivable. Clean boundaries don't just help other engineers — they help future-you.&lt;/p&gt;

&lt;p&gt;If you're mid-break on something right now: the code will still make sense when you get back. Go take care of what you need to.&lt;/p&gt;


&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Nevin100" rel="noopener noreferrer"&gt;
        Nevin100
      &lt;/a&gt; / &lt;a href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;
        DevdocxAI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DevDocxAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates engineering documentation by deeply understanding you…DevDocAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates doc. by understanding deeply.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DevDocxAI 🤖📄&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;DevDocxAi is a production-grade multi-agent LangGraph system that automatically generates and updates engineering documentation from your GitHub codebase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e"&gt;&lt;img src="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e" alt="Python"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069"&gt;&lt;img src="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265" alt="LangGraph"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c"&gt;&lt;img src="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c" alt="PostgreSQL"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265" alt="Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚨 The Problem:&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Every engineering team has the same dirty secret — &lt;strong&gt;the docs are lying.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not intentionally. Code moves fast, documentation doesn't.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New dev joins → 2 weeks reading outdated wikis&lt;/li&gt;
&lt;li&gt;Senior engineers constantly interrupted with "what does this do?"&lt;/li&gt;
&lt;li&gt;PR gets merged → docs never updated&lt;/li&gt;
&lt;li&gt;Generic RAG chatbots don't understand code &lt;em&gt;structure&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DevDocAI fixes this.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ What It Does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Connects to your GitHub repo&lt;/strong&gt; via OAuth&lt;/li&gt;
&lt;li&gt;🌳 &lt;strong&gt;Parses your codebase at the AST level&lt;/strong&gt; — understands functions, classes, modules&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Auto-generates structured documentation&lt;/strong&gt; per module and function&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Updates docs on every PR merge&lt;/strong&gt; via GitHub webhooks&lt;/li&gt;
&lt;li&gt;👀 &lt;strong&gt;Human-in-the-Loop review&lt;/strong&gt; — you approve before anything goes live&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Onboarding chatbot&lt;/strong&gt; — new devs ask questions, get answers from live code&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤖 Agent Pipeline&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;START
  ↓
codebase_parser&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;&lt;em&gt;Building in public — with real gaps, and real comebacks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;python&lt;/code&gt; &lt;code&gt;nextjs&lt;/code&gt; &lt;code&gt;ai&lt;/code&gt; &lt;code&gt;langgraph&lt;/code&gt; &lt;code&gt;fastapi&lt;/code&gt; &lt;code&gt;typescript&lt;/code&gt; &lt;code&gt;opensource&lt;/code&gt; &lt;code&gt;webdev&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>mcp</category>
      <category>langgraph</category>
      <category>langchain</category>
    </item>
    <item>
      <title>Building DevDocAI — A Production Multi-Agent LangGraph System | Part 3 - GitHub Webhooks, Redis Caching</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Sun, 14 Jun 2026 16:35:01 +0000</pubDate>
      <link>https://dev.to/nevin100/building-devdocai-a-production-multi-agent-langgraph-system-part-3-github-webhooks-redis-1mgk</link>
      <guid>https://dev.to/nevin100/building-devdocai-a-production-multi-agent-langgraph-system-part-3-github-webhooks-redis-1mgk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series:&lt;/strong&gt; Building DevDocAI — A Production Multi-Agent LangGraph System&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3&lt;/strong&gt; — GitHub Webhooks, Redis Caching &amp;amp; Making DevDocAI Truly Autonomous&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Real Talk First
&lt;/h2&gt;

&lt;p&gt;Between Part 2 and this post, I had university exams.&lt;/p&gt;

&lt;p&gt;Not just one. A full exam week.&lt;/p&gt;

&lt;p&gt;And honestly? I almost paused the project.&lt;/p&gt;

&lt;p&gt;But then I thought — if I can't build while life is happening, what's the point?&lt;/p&gt;

&lt;p&gt;So I kept going. Exams in the morning, code at night.&lt;/p&gt;

&lt;p&gt;This post is the result of that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;By the end of Part 2, DevDocAI had:&lt;/p&gt;

&lt;p&gt;✅ A fully working LangGraph multi-agent pipeline&lt;br&gt;&lt;br&gt;
✅ AST-level codebase parsing&lt;br&gt;&lt;br&gt;
✅ LLM-powered documentation generation&lt;br&gt;&lt;br&gt;
✅ Brave Search enrichment&lt;br&gt;&lt;br&gt;
✅ Human-in-the-Loop review&lt;br&gt;&lt;br&gt;
✅ Qdrant vector store + RAG chatbot  &lt;/p&gt;

&lt;p&gt;But there was one major problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was still manual.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Someone had to trigger the pipeline every time.&lt;/p&gt;

&lt;p&gt;That's not autonomous documentation. That's just a fancy script.&lt;/p&gt;

&lt;p&gt;Phase 5 fixes that.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Phase 5 Adds
&lt;/h2&gt;

&lt;p&gt;Two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Webhooks&lt;/strong&gt; — DevDocAI listens for PR merges and auto-triggers the pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Caching&lt;/strong&gt; — pipeline status, docs, and repo data cached for speed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After this phase, the flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer merges a PR
        ↓
GitHub sends webhook to DevDocAI
        ↓
DevDocAI finds the repo in DB
        ↓
Verifies the webhook signature
        ↓
Creates a PipelineRun record
        ↓
Triggers the full agent pipeline
        ↓
Docs auto-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Zero manual intervention.&lt;/p&gt;


&lt;h2&gt;
  
  
  GitHub Webhooks — How It Works
&lt;/h2&gt;

&lt;p&gt;A GitHub webhook is simple.&lt;/p&gt;

&lt;p&gt;When something happens in a repo (PR merged, push, etc.), GitHub sends a POST request to a URL you configure.&lt;/p&gt;

&lt;p&gt;DevDocAI listens at &lt;code&gt;/webhooks/github&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But there's a security problem.&lt;/p&gt;

&lt;p&gt;Anyone can send a fake POST request to that URL.&lt;/p&gt;

&lt;p&gt;GitHub solves this with &lt;strong&gt;HMAC-SHA256 signatures&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every webhook request has an &lt;code&gt;X-Hub-Signature-256&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;It's a hash of the payload signed with a shared secret.&lt;/p&gt;

&lt;p&gt;We verify it before doing anything:&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;verify_github_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signature&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;secret&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sha256=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&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;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare_digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If the signature doesn't match, request is rejected.&lt;/p&gt;

&lt;p&gt;Simple. Secure.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Webhook Handler
&lt;/h2&gt;

&lt;p&gt;The full webhook flow in code:&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="nd"&gt;@router.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/github&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;github_webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...):&lt;/span&gt;

    &lt;span class="c1"&gt;# Only care about merged PRs
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;closed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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;ignored&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Find repo in our DB
&lt;/span&gt;    &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_repo_by_github_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;github_repo_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Verify signature
&lt;/span&gt;    &lt;span class="nf"&gt;verify_github_signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload_bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create PipelineRun record
&lt;/span&gt;    &lt;span class="n"&gt;pipeline_run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PipelineRun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pr_merge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pr_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pr_number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Cache pipeline status in Redis
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;cache_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;pipeline_status_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&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;status&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;running&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;# Trigger the pipeline
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;run_pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc_graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Clean, sequential, easy to follow.&lt;/p&gt;

&lt;p&gt;Each step has one job.&lt;/p&gt;


&lt;h2&gt;
  
  
  Redis Caching — Why It Matters
&lt;/h2&gt;

&lt;p&gt;Every time someone opens the dashboard, should we query PostgreSQL for everything?&lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;That's where Redis comes in.&lt;/p&gt;

&lt;p&gt;Three main cache keys:&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="nf"&gt;repo_docs_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# "repo:{id}:docs"
&lt;/span&gt;&lt;span class="nf"&gt;pipeline_status_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# "pipeline:{thread_id}:status"
&lt;/span&gt;&lt;span class="nf"&gt;user_repos_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;# "user:{id}:repos"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When a PR triggers the pipeline, old docs cache is invalidated immediately:&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;await&lt;/span&gt; &lt;span class="nf"&gt;cache_delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;repo_docs_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When someone checks pipeline status, it comes from Redis — not a DB query.&lt;/p&gt;

&lt;p&gt;Fast. Cheap. Simple.&lt;/p&gt;


&lt;h2&gt;
  
  
  What the Full System Looks Like Now
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend/
├── auth/
│   ├── jwt.py
│   ├── github_oauth.py
│   └── routes.py
├── db/
│   ├── database.py
│   └── models.py
├── repositories/
│   └── user_repository.py
├── schemas/
│   └── auth_schemas.py
├── services/
│   └── auth_service.py
├── utils/
│   ├── helper_auth.py
│   └── encryption.py
├── mcp/
│   └── github_server.py
├── agents/
│   ├── codebase_parser.py
│   ├── doc_generator.py
│   ├── brave_researcher.py
│   ├── doc_publisher.py
│   └── onboarding_chatbot.py
├── graph/
│   ├── state.py
│   ├── pipeline.py
│   └── hitl.py
├── vectorstore/
│   ├── embeddings.py
│   └── qdrant_store.py
├── webhooks/
│   └── github_pr.py       ← new
├── cache/
│   └── redis_client.py    ← new
└── main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Backend is complete.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Endpoints Now
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET   /health
POST  /auth/register
POST  /auth/login
GET   /auth/github
POST  /auth/github/callback
GET   /auth/me
POST  /webhooks/github      ← new
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building During Exams — What I Learned
&lt;/h2&gt;

&lt;p&gt;Honestly, shipping Phase 5 while having exams taught me more than just code.&lt;/p&gt;

&lt;p&gt;A few things I noticed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constraints force focus.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
When you only have 2 hours, you don't waste time on perfect folder naming or over-engineering. You build what matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Momentum is everything.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Missing one day makes it easier to miss two. Shipping something small every day — even just one file — keeps the project alive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;University teaches you to work under pressure. Building teaches you to create under pressure.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Both matter. They're not enemies.&lt;/p&gt;

&lt;p&gt;I'm not saying skip studying. I'm saying you don't have to choose between learning and building.&lt;/p&gt;

&lt;p&gt;Do both. It's harder. It's worth it.&lt;/p&gt;


&lt;h2&gt;
  
  
  Key Technical Learnings from Phase 5
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Always verify webhook signatures.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Without HMAC verification, anyone can trigger your pipeline. Never skip this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Invalidate cache on state change.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
When docs update, old cache must go. Stale cache is worse than no cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Background tasks need proper state.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
When the webhook triggers a pipeline, it runs async. Make sure state is fully initialized before kicking it off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. &lt;code&gt;psycopg[binary]&lt;/code&gt; is required for LangGraph PostgreSQL checkpointer on Windows.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Spent more time than I'd like to admit on this one.&lt;/p&gt;


&lt;h2&gt;
  
  
  What's Next — Part 4
&lt;/h2&gt;

&lt;p&gt;Phase 6 is the &lt;strong&gt;Next.js frontend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Three pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard&lt;/strong&gt; — connected repos, pipeline status, doc overview&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review Panel&lt;/strong&gt; — HITL approval UI (approve/reject generated docs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat&lt;/strong&gt; — onboarding chatbot interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where DevDocAI becomes something you can actually show someone without saying "trust me, it works."&lt;/p&gt;

&lt;p&gt;Exams are still going. Building is still happening.&lt;/p&gt;

&lt;p&gt;Part 4 dropping soon. 🚀&lt;/p&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygu9toyrdg70ns00zuw0.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.amazonaws.com%2Fuploads%2Farticles%2Fygu9toyrdg70ns00zuw0.png" alt="Code Base SS" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Nevin100" rel="noopener noreferrer"&gt;
        Nevin100
      &lt;/a&gt; / &lt;a href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;
        DevdocxAI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DevDocxAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates engineering documentation by deeply understanding you…DevDocAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates doc. by understanding deeply.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DevDocxAI 🤖📄&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;DevDocxAi is a production-grade multi-agent LangGraph system that automatically generates and updates engineering documentation from your GitHub codebase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e"&gt;&lt;img src="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e" alt="Python"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069"&gt;&lt;img src="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265" alt="LangGraph"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c"&gt;&lt;img src="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c" alt="PostgreSQL"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265" alt="Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚨 The Problem:&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Every engineering team has the same dirty secret — &lt;strong&gt;the docs are lying.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not intentionally. Code moves fast, documentation doesn't.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New dev joins → 2 weeks reading outdated wikis&lt;/li&gt;
&lt;li&gt;Senior engineers constantly interrupted with "what does this do?"&lt;/li&gt;
&lt;li&gt;PR gets merged → docs never updated&lt;/li&gt;
&lt;li&gt;Generic RAG chatbots don't understand code &lt;em&gt;structure&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DevDocAI fixes this.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ What It Does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Connects to your GitHub repo&lt;/strong&gt; via OAuth&lt;/li&gt;
&lt;li&gt;🌳 &lt;strong&gt;Parses your codebase at the AST level&lt;/strong&gt; — understands functions, classes, modules&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Auto-generates structured documentation&lt;/strong&gt; per module and function&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Updates docs on every PR merge&lt;/strong&gt; via GitHub webhooks&lt;/li&gt;
&lt;li&gt;👀 &lt;strong&gt;Human-in-the-Loop review&lt;/strong&gt; — you approve before anything goes live&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Onboarding chatbot&lt;/strong&gt; — new devs ask questions, get answers from live code&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤖 Agent Pipeline&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;START
  ↓
codebase_parser&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;&lt;em&gt;Building in public — through exams, late nights, and all.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;python&lt;/code&gt; &lt;code&gt;ai&lt;/code&gt; &lt;code&gt;langgraph&lt;/code&gt; &lt;code&gt;fastapi&lt;/code&gt; &lt;code&gt;redis&lt;/code&gt; &lt;code&gt;webhooks&lt;/code&gt; &lt;code&gt;opensource&lt;/code&gt; &lt;code&gt;webdev&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>fastapi</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building DevDocAI - An AI That Writes Your Docs Automatically | Part 2: LangGraph Core, Agents &amp; RAG</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Sun, 07 Jun 2026 13:36:28 +0000</pubDate>
      <link>https://dev.to/nevin100/-building-devdocai-an-ai-that-writes-your-docs-automatically-part-2-langgraph-core-agents--3j27</link>
      <guid>https://dev.to/nevin100/-building-devdocai-an-ai-that-writes-your-docs-automatically-part-2-langgraph-core-agents--3j27</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series:&lt;/strong&gt; Building DevDocAI — A Production Multi-Agent LangGraph System&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2&lt;/strong&gt; — LangGraph Core, Human-in-the-Loop Workflows, Agents &amp;amp; RAG&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;In Part 1, I built the foundation of DevDocAI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI backend&lt;/li&gt;
&lt;li&gt;PostgreSQL database&lt;/li&gt;
&lt;li&gt;JWT authentication&lt;/li&gt;
&lt;li&gt;GitHub OAuth&lt;/li&gt;
&lt;li&gt;MCP server for GitHub tools&lt;/li&gt;
&lt;li&gt;Clean layered architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, the infrastructure was ready, but the actual AI system didn't exist yet.&lt;/p&gt;

&lt;p&gt;This phase changes that.&lt;/p&gt;

&lt;p&gt;In this article, I'm covering &lt;strong&gt;Phase 3 and Phase 4&lt;/strong&gt;, where DevDocAI finally becomes a real multi-agent system powered by LangGraph.&lt;/p&gt;




&lt;h2&gt;
  
  
  What We Built in This Phase
&lt;/h2&gt;

&lt;p&gt;The goal was simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Take a GitHub repository and turn it into living documentation through an orchestrated AI workflow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make that happen, I built:&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 3 — LangGraph Core
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;State Management&lt;/li&gt;
&lt;li&gt;Workflow Pipeline&lt;/li&gt;
&lt;li&gt;Human-in-the-Loop (HITL)&lt;/li&gt;
&lt;li&gt;PostgreSQL Checkpointing&lt;/li&gt;
&lt;li&gt;Conditional Routing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Phase 4 — Agents &amp;amp; RAG
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;AST-based Code Parser Agent&lt;/li&gt;
&lt;li&gt;Documentation Generator Agent&lt;/li&gt;
&lt;li&gt;Brave Researcher Agent&lt;/li&gt;
&lt;li&gt;Documentation Publisher Agent&lt;/li&gt;
&lt;li&gt;Qdrant Vector Store&lt;/li&gt;
&lt;li&gt;Embeddings Pipeline&lt;/li&gt;
&lt;li&gt;Onboarding Chatbot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where DevDocAI went from "backend project" to "actual AI product."&lt;/p&gt;




&lt;h2&gt;
  
  
  The Updated Workflow
&lt;/h2&gt;

&lt;p&gt;The complete pipeline now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;START
  ↓
codebase_parser
  ↓
doc_generator
  ↓
brave_researcher
  ↓
HITL checkpoint
  ↓
doc_publisher
  ↓
END

Parallel

onboarding_chatbot
      ↓
  Vector Store
      ↓
 Generated Docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Every node performs a specific task and passes information to the next node through a shared graph state.&lt;/p&gt;


&lt;h1&gt;
  
  
  Phase 3 — LangGraph Core
&lt;/h1&gt;

&lt;p&gt;Before building agents, I needed a reliable workflow engine.&lt;/p&gt;

&lt;p&gt;This is where LangGraph came in.&lt;/p&gt;

&lt;p&gt;Unlike a simple chain, LangGraph allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stateful execution&lt;/li&gt;
&lt;li&gt;Checkpointing&lt;/li&gt;
&lt;li&gt;Human approval workflows&lt;/li&gt;
&lt;li&gt;Conditional routing&lt;/li&gt;
&lt;li&gt;Resume after interruption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exactly what a production documentation system needs.&lt;/p&gt;


&lt;h2&gt;
  
  
  State Management
&lt;/h2&gt;

&lt;p&gt;The first thing I built was a central state object.&lt;/p&gt;

&lt;p&gt;Every agent in the graph reads from and writes to the same state.&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;class&lt;/span&gt; &lt;span class="nc"&gt;DevDocState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;repo_full_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;repo_raw_content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

    &lt;span class="n"&gt;parsed_structure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;
    &lt;span class="n"&gt;generated_docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

    &lt;span class="n"&gt;current_step&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;review_status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;dev_notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

    &lt;span class="n"&gt;final_docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Think of this as the memory of the entire workflow.&lt;/p&gt;

&lt;p&gt;Instead of passing dozens of variables between agents, everything flows through a single structured state.&lt;/p&gt;

&lt;p&gt;This makes debugging significantly easier.&lt;/p&gt;


&lt;h2&gt;
  
  
  Building the Pipeline
&lt;/h2&gt;

&lt;p&gt;Once the state was defined, I created the graph itself.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;START
  ↓
code_parser_node
  ↓
doc_generator_node
  ↓
hitl_review_node
  ↓
doc_publisher_node
  ↓
END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each node performs one responsibility.&lt;/p&gt;
&lt;h3&gt;
  
  
  Code Parser Node
&lt;/h3&gt;

&lt;p&gt;Reads the repository and analyzes the code structure.&lt;/p&gt;
&lt;h3&gt;
  
  
  Documentation Generator Node
&lt;/h3&gt;

&lt;p&gt;Creates documentation using the parsed output.&lt;/p&gt;
&lt;h3&gt;
  
  
  HITL Node
&lt;/h3&gt;

&lt;p&gt;Pauses execution and waits for a human decision.&lt;/p&gt;
&lt;h3&gt;
  
  
  Publisher Node
&lt;/h3&gt;

&lt;p&gt;Publishes approved documentation.&lt;/p&gt;

&lt;p&gt;This separation keeps the graph modular and easy to extend.&lt;/p&gt;


&lt;h2&gt;
  
  
  Human-in-the-Loop (HITL)
&lt;/h2&gt;

&lt;p&gt;This was one of the most interesting parts of the project.&lt;/p&gt;

&lt;p&gt;I didn't want an AI that automatically pushes documentation to production.&lt;/p&gt;

&lt;p&gt;Developers need control.&lt;/p&gt;

&lt;p&gt;So the graph pauses before publishing.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generated Docs
      ↓
    Review
      ↓
 Approved ? 
   /     \
 Yes      No
  ↓        ↓
Publish   Stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The workflow literally waits for a developer's decision.&lt;/p&gt;

&lt;p&gt;This is not a prompt-based approval.&lt;/p&gt;

&lt;p&gt;This is actual workflow orchestration.&lt;/p&gt;

&lt;p&gt;The graph execution stops and resumes later based on user input.&lt;/p&gt;


&lt;h2&gt;
  
  
  PostgreSQL Checkpointing
&lt;/h2&gt;

&lt;p&gt;A paused workflow is useless if the state disappears.&lt;/p&gt;

&lt;p&gt;That's why I implemented checkpoint persistence.&lt;/p&gt;

&lt;p&gt;The complete graph state is stored in PostgreSQL.&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;checkpoint&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;
&lt;span class="n"&gt;resume&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;restore&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;
&lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="n"&gt;execution&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workflow survives server restarts&lt;/li&gt;
&lt;li&gt;Long-running executions become possible&lt;/li&gt;
&lt;li&gt;Human approval can happen hours later&lt;/li&gt;
&lt;li&gt;Full auditability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was one of the biggest advantages of choosing LangGraph.&lt;/p&gt;


&lt;h2&gt;
  
  
  Conditional Routing
&lt;/h2&gt;

&lt;p&gt;After review, the graph makes a decision.&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;should_publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review_status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;approved&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;publish&lt;/span&gt;&lt;span class="sh"&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;reject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The graph dynamically routes execution.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review
   ↓
Approved?
   ↓
 ┌───────┬────────┐
 │ Yes   │ No     │
 ↓       ↓
Publish  Reject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Simple idea.&lt;/p&gt;

&lt;p&gt;Very powerful in production workflows.&lt;/p&gt;


&lt;h1&gt;
  
  
  Phase 4 — Building the Agents
&lt;/h1&gt;

&lt;p&gt;Once the graph was ready, it was time to build the intelligence layer.&lt;/p&gt;

&lt;p&gt;I created four specialized agents.&lt;/p&gt;

&lt;p&gt;Each one solves a specific problem.&lt;/p&gt;


&lt;h2&gt;
  
  
  Agent 1 — Codebase Parser
&lt;/h2&gt;

&lt;p&gt;This agent is responsible for understanding the repository.&lt;/p&gt;

&lt;p&gt;Instead of treating source code as plain text, it analyzes the code using Python's AST.&lt;/p&gt;
&lt;h3&gt;
  
  
  What it extracts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Functions&lt;/li&gt;
&lt;li&gt;Classes&lt;/li&gt;
&lt;li&gt;Imports&lt;/li&gt;
&lt;li&gt;Modules&lt;/li&gt;
&lt;li&gt;Dependencies&lt;/li&gt;
&lt;li&gt;Documentation patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&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;amount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The parser understands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function name&lt;/li&gt;
&lt;li&gt;Parameters&lt;/li&gt;
&lt;li&gt;Relationships&lt;/li&gt;
&lt;li&gt;Dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not just raw text.&lt;/p&gt;

&lt;p&gt;Actual code structure.&lt;/p&gt;

&lt;p&gt;This becomes the foundation for documentation generation.&lt;/p&gt;


&lt;h2&gt;
  
  
  Agent 2 — Documentation Generator
&lt;/h2&gt;

&lt;p&gt;After parsing, the next challenge is turning code into useful documentation.&lt;/p&gt;

&lt;p&gt;This agent takes structured information and generates docs.&lt;/p&gt;

&lt;p&gt;Capabilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Markdown generation&lt;/li&gt;
&lt;li&gt;HTML generation&lt;/li&gt;
&lt;li&gt;Function explanations&lt;/li&gt;
&lt;li&gt;Usage examples&lt;/li&gt;
&lt;li&gt;API documentation&lt;/li&gt;
&lt;li&gt;Multiple documentation styles
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:
Parsed AST Structure

Output:
Developer-Friendly Documentation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is the core value proposition of DevDocAI.&lt;/p&gt;


&lt;h2&gt;
  
  
  Agent 3 — Brave Researcher
&lt;/h2&gt;

&lt;p&gt;Documentation generated purely from code is often incomplete.&lt;/p&gt;

&lt;p&gt;Libraries, frameworks and external tools also need context.&lt;/p&gt;

&lt;p&gt;To solve this, I built the Brave Researcher.&lt;/p&gt;

&lt;p&gt;It uses the Brave Search API to gather additional information.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Library explanations&lt;/li&gt;
&lt;li&gt;Framework documentation&lt;/li&gt;
&lt;li&gt;Best practices&lt;/li&gt;
&lt;li&gt;External references&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates richer documentation than code analysis alone.&lt;/p&gt;


&lt;h2&gt;
  
  
  Agent 4 — Documentation Publisher
&lt;/h2&gt;

&lt;p&gt;Generating docs isn't enough.&lt;/p&gt;

&lt;p&gt;They need to be distributed.&lt;/p&gt;

&lt;p&gt;The publisher agent handles that responsibility.&lt;/p&gt;

&lt;p&gt;Supported targets include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Wiki&lt;/li&gt;
&lt;li&gt;README generation&lt;/li&gt;
&lt;li&gt;File storage&lt;/li&gt;
&lt;li&gt;Versioned documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of the system doesn't care where docs go.&lt;/p&gt;

&lt;p&gt;The publisher abstracts that away.&lt;/p&gt;


&lt;h1&gt;
  
  
  Adding RAG with Qdrant
&lt;/h1&gt;

&lt;p&gt;The next challenge was onboarding.&lt;/p&gt;

&lt;p&gt;Imagine a new engineer joins a project.&lt;/p&gt;

&lt;p&gt;Instead of reading hundreds of files, they should be able to ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does the authentication flow look like?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which service handles payment processing?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make that possible, I added Retrieval-Augmented Generation (RAG).&lt;/p&gt;


&lt;h2&gt;
  
  
  Vector Store Architecture
&lt;/h2&gt;

&lt;p&gt;Generated documentation is embedded and stored in Qdrant.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generated Docs
       ↓
Embeddings
       ↓
Qdrant
       ↓
Semantic Search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Instead of keyword matching, the system performs semantic retrieval.&lt;/p&gt;

&lt;p&gt;This allows developers to ask natural language questions.&lt;/p&gt;


&lt;h2&gt;
  
  
  Embeddings Pipeline
&lt;/h2&gt;

&lt;p&gt;Every document is converted into vectors.&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;Document&lt;/span&gt;
   &lt;span class="err"&gt;↓&lt;/span&gt;
&lt;span class="n"&gt;Embedding&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt;
   &lt;span class="err"&gt;↓&lt;/span&gt;
&lt;span class="n"&gt;Vector&lt;/span&gt;
   &lt;span class="err"&gt;↓&lt;/span&gt;
&lt;span class="n"&gt;Qdrant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These vectors capture meaning rather than exact words.&lt;/p&gt;

&lt;p&gt;That makes retrieval dramatically better.&lt;/p&gt;


&lt;h1&gt;
  
  
  The Onboarding Chatbot
&lt;/h1&gt;

&lt;p&gt;The final piece of Phase 4 was the onboarding assistant.&lt;/p&gt;

&lt;p&gt;This chatbot sits on top of the vector store.&lt;/p&gt;

&lt;p&gt;Workflow:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer Question
        ↓
Vector Search
        ↓
Relevant Docs
        ↓
LLM
        ↓
Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now a developer can ask questions about the codebase without manually searching through files.&lt;/p&gt;

&lt;p&gt;The answers come from generated documentation and repository knowledge.&lt;/p&gt;

&lt;p&gt;Not generic internet responses.&lt;/p&gt;


&lt;h1&gt;
  
  
  Why I Chose Specialized Agents
&lt;/h1&gt;

&lt;p&gt;One giant prompt could technically do everything.&lt;/p&gt;

&lt;p&gt;But that's not how production systems scale.&lt;/p&gt;

&lt;p&gt;Instead:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parser Agent
      ↓
Research Agent
      ↓
Generator Agent
      ↓
Publisher Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each agent has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One responsibility&lt;/li&gt;
&lt;li&gt;Clear inputs&lt;/li&gt;
&lt;li&gt;Clear outputs&lt;/li&gt;
&lt;li&gt;Independent testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the system easier to maintain and improve.&lt;/p&gt;


&lt;h1&gt;
  
  
  What the Project Structure Looks Like Now
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend/
├── agents/
│   ├── brave_researcher.py
│   ├── codebase_parser.py
│   ├── doc_generator.py
│   ├── doc_publisher.py
│   └── onboarding_chatbot.py
│
├── graph/
│   ├── state.py
│   ├── pipeline.py
│   └── hitl.py
│
└── vectorstore/
    ├── embeddings.py
    └── qdrant_client.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The architecture is starting to resemble a real production AI platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fig53cyhkaaxw5u31q1p9.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fig53cyhkaaxw5u31q1p9.jpg" alt="CodeBase File Structure" width="799" height="424"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Key Learnings from Phase 3 &amp;amp; 4
&lt;/h1&gt;
&lt;h2&gt;
  
  
  1. Agents Need Structure
&lt;/h2&gt;

&lt;p&gt;Most AI projects fail because every responsibility gets stuffed into one prompt.&lt;/p&gt;

&lt;p&gt;Breaking responsibilities into specialized agents makes the system dramatically more reliable.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Human Approval Matters
&lt;/h2&gt;

&lt;p&gt;Fully autonomous documentation publishing sounds cool until it publishes something wrong.&lt;/p&gt;

&lt;p&gt;HITL workflows provide the safety net production systems need.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. RAG Is Only As Good As Your Documents
&lt;/h2&gt;

&lt;p&gt;A chatbot is useless if the underlying knowledge base is poor.&lt;/p&gt;

&lt;p&gt;Investing in quality documentation generation improves everything downstream.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. State Management Becomes Critical
&lt;/h2&gt;

&lt;p&gt;Once workflows span multiple agents, checkpoints and persistence become mandatory.&lt;/p&gt;

&lt;p&gt;Without state management, debugging becomes a nightmare.&lt;/p&gt;


&lt;h1&gt;
  
  
  What's Next — Part 3
&lt;/h1&gt;

&lt;p&gt;The core AI system is now complete.&lt;/p&gt;

&lt;p&gt;Next, I'll focus on Phase 5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Webhooks&lt;/li&gt;
&lt;li&gt;Automatic PR Detection&lt;/li&gt;
&lt;li&gt;Incremental Documentation Updates&lt;/li&gt;
&lt;li&gt;Redis Caching&lt;/li&gt;
&lt;li&gt;Event-Driven Pipeline Execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where DevDocAI becomes truly autonomous.&lt;/p&gt;

&lt;p&gt;Every merged PR will automatically trigger documentation updates.&lt;/p&gt;

&lt;p&gt;No manual intervention required.&lt;/p&gt;


&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Nevin100" rel="noopener noreferrer"&gt;
        Nevin100
      &lt;/a&gt; / &lt;a href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;
        DevdocxAI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DevDocxAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates engineering documentation by deeply understanding you…DevDocAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates doc. by understanding deeply.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DevDocxAI 🤖📄&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;DevDocxAi is a production-grade multi-agent LangGraph system that automatically generates and updates engineering documentation from your GitHub codebase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e"&gt;&lt;img src="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e" alt="Python"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069"&gt;&lt;img src="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265" alt="LangGraph"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c"&gt;&lt;img src="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c" alt="PostgreSQL"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265" alt="Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚨 The Problem:&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Every engineering team has the same dirty secret — &lt;strong&gt;the docs are lying.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not intentionally. Code moves fast, documentation doesn't.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New dev joins → 2 weeks reading outdated wikis&lt;/li&gt;
&lt;li&gt;Senior engineers constantly interrupted with "what does this do?"&lt;/li&gt;
&lt;li&gt;PR gets merged → docs never updated&lt;/li&gt;
&lt;li&gt;Generic RAG chatbots don't understand code &lt;em&gt;structure&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DevDocAI fixes this.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ What It Does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Connects to your GitHub repo&lt;/strong&gt; via OAuth&lt;/li&gt;
&lt;li&gt;🌳 &lt;strong&gt;Parses your codebase at the AST level&lt;/strong&gt; — understands functions, classes, modules&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Auto-generates structured documentation&lt;/strong&gt; per module and function&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Updates docs on every PR merge&lt;/strong&gt; via GitHub webhooks&lt;/li&gt;
&lt;li&gt;👀 &lt;strong&gt;Human-in-the-Loop review&lt;/strong&gt; — you approve before anything goes live&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Onboarding chatbot&lt;/strong&gt; — new devs ask questions, get answers from live code&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤖 Agent Pipeline&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;START
  ↓
codebase_parser&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;&lt;em&gt;Building in public. Part 3 dropping soon.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;python&lt;/code&gt; &lt;code&gt;ai&lt;/code&gt; &lt;code&gt;langgraph&lt;/code&gt; &lt;code&gt;langchain&lt;/code&gt; &lt;code&gt;rag&lt;/code&gt; &lt;code&gt;fastapi&lt;/code&gt; &lt;code&gt;opensource&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>python</category>
      <category>agents</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building DevDocAI - An AI That Writes Your Docs | Part 1: Foundation</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Fri, 05 Jun 2026 08:57:25 +0000</pubDate>
      <link>https://dev.to/nevin100/building-devdocai-an-ai-that-writes-your-docs-part-1-foundation-5cjh</link>
      <guid>https://dev.to/nevin100/building-devdocai-an-ai-that-writes-your-docs-part-1-foundation-5cjh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Series:&lt;/strong&gt; Building DevDocAI — A Production Multi-Agent LangGraph System&lt;br&gt;
&lt;strong&gt;Part 1 of 6&lt;/strong&gt; — Foundation: Backend, Auth, DB, GitHub OAuth, MCP Server&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;Every engineering team has the same dirty secret: &lt;strong&gt;the docs are lying.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not intentionally. Code moves fast, documentation doesn't. A new dev joins → spends 2 weeks reading outdated wikis → still has to disturb 3 senior engineers just to understand one service.&lt;/p&gt;

&lt;p&gt;I got tired of it. So I'm building &lt;strong&gt;DevDocAI&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is DevDocAI?
&lt;/h2&gt;

&lt;p&gt;DevDocAI is a &lt;strong&gt;production-grade multi-agent LangGraph system&lt;/strong&gt; that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connects to your GitHub repo&lt;/li&gt;
&lt;li&gt;Reads your codebase at the &lt;strong&gt;AST level&lt;/strong&gt; (not just text — actual code structure)&lt;/li&gt;
&lt;li&gt;Auto-generates structured documentation per module/function&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updates docs automatically&lt;/strong&gt; every time a PR gets merged&lt;/li&gt;
&lt;li&gt;Has an &lt;strong&gt;onboarding chatbot&lt;/strong&gt; — new devs can ask "what does this function do?" and get real answers from live code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key word is &lt;strong&gt;agent&lt;/strong&gt; — not just a RAG chatbot. This system understands your code.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Full Agent Pipeline (What I'm Building)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;START
  ↓
codebase_parser      ← AST-level parsing of GitHub repo
  ↓
doc_generator        ← LLM generates structured docs per module/function
  ↓
brave_researcher     ← enriches with external context (libraries, best practices)
  ↓
HITL checkpoint      ← YOU review generated docs before publish
  ↓
doc_publisher        ← saves to DB + updates vector store
  ↓
pr_watcher           ← GitHub webhook re-triggers on every PR merge
  ↓
END

Parallel → onboarding_chatbot ← RAG over vector store for new devs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;strong&gt;HITL (Human-in-the-Loop)&lt;/strong&gt; part is what makes this real. The LangGraph pipeline literally &lt;em&gt;pauses&lt;/em&gt;, waits for a dev to approve via the frontend, then resumes. Not just vibes — actual workflow.&lt;/p&gt;


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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent Framework&lt;/td&gt;
&lt;td&gt;LangGraph&lt;/td&gt;
&lt;td&gt;Multi-agent, HITL, checkpointing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;FastAPI + Python&lt;/td&gt;
&lt;td&gt;Async, fast, clean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Next.js + Tailwind&lt;/td&gt;
&lt;td&gt;(coming Phase 6)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;Groq llama-3.3-70b&lt;/td&gt;
&lt;td&gt;Blazing fast inference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Embeddings&lt;/td&gt;
&lt;td&gt;Cohere&lt;/td&gt;
&lt;td&gt;Best-in-class embeddings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vector DB&lt;/td&gt;
&lt;td&gt;Qdrant&lt;/td&gt;
&lt;td&gt;Production-grade, pure Python client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Search&lt;/td&gt;
&lt;td&gt;Brave Search API&lt;/td&gt;
&lt;td&gt;Dev-focused, privacy-first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;LangSmith&lt;/td&gt;
&lt;td&gt;Agent traces, debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool Protocol&lt;/td&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;td&gt;Modern tool standard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;JWT + GitHub OAuth&lt;/td&gt;
&lt;td&gt;Secure, industry standard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;Redis (Upstash)&lt;/td&gt;
&lt;td&gt;(coming Phase 5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;AWS S3&lt;/td&gt;
&lt;td&gt;Doc storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Neon (prod), Docker (dev)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;ECR + ECS Fargate&lt;/td&gt;
&lt;td&gt;(coming Phase 7)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD&lt;/td&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;(coming Phase 7)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Architecture — The Pattern I Follow
&lt;/h2&gt;

&lt;p&gt;Every layer has &lt;strong&gt;one job&lt;/strong&gt;. No exceptions.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route      → HTTP only (request/response)
    ↓
Service    → Business logic
    ↓
Repository → DB queries only
    ↓
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is what separates a demo from something real. When 5 engineers touch the same codebase, this pattern saves you.&lt;/p&gt;
&lt;h3&gt;
  
  
  Folder Structure
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend/
├── auth/
│   ├── jwt.py              ← token create/verify
│   ├── github_oauth.py     ← GitHub OAuth flow
│   └── routes.py           ← HTTP layer only
├── db/
│   ├── database.py         ← async PostgreSQL
│   └── models.py           ← SQLAlchemy models
├── repositories/
│   └── user_repository.py  ← all DB queries here
├── schemas/
│   └── auth_schemas.py     ← Pydantic request/response
├── services/
│   └── auth_service.py     ← business logic
├── utils/
│   ├── helper_auth.py      ← bcrypt helpers
│   └── encryption.py       ← Fernet token encryption
├── mcp/
│   └── github_server.py    ← GitHub tools for agents
├── agents/                 ← Phase 4
├── graph/                  ← Phase 3
├── webhooks/               ← Phase 5
└── main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Database Design
&lt;/h2&gt;

&lt;p&gt;4 tables, all connected:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  └── Repository
          ├── Document       ← generated docs (PENDING → APPROVED → PUBLISHED)
          └── PipelineRun    ← LangGraph execution tracking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A few production decisions I made:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UUIDs over integer IDs&lt;/strong&gt; — no sequential ID enumeration attacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fernet encryption for GitHub tokens&lt;/strong&gt; — never store access tokens in plaintext. Ever.&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="c1"&gt;# utils/encryption.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cryptography.fernet&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Fernet&lt;/span&gt;

&lt;span class="n"&gt;_fernet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Fernet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ENCRYPTION_KEY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&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="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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_fernet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&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="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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_fernet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Indexes on Document table&lt;/strong&gt; — &lt;code&gt;repo_id&lt;/code&gt;, &lt;code&gt;file_path&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt; are all indexed because these will be queried constantly at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DocStatus enum&lt;/strong&gt; for proper state machine:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PENDING → APPROVED → PUBLISHED
PENDING → REJECTED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GitHub OAuth Flow
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frontend → GET /auth/github  →  GitHub redirect URL
              ↓
    User authorizes on GitHub
              ↓
GitHub → POST /auth/github/callback?code=xxx
              ↓
    Code → access_token exchange
              ↓
    Token encrypted → stored in DB
              ↓
    JWT returned → Frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Clean separation — &lt;code&gt;routes.py&lt;/code&gt; only handles HTTP, &lt;code&gt;auth_service.py&lt;/code&gt; has all the logic, &lt;code&gt;user_repository.py&lt;/code&gt; handles all DB queries.&lt;/p&gt;


&lt;h2&gt;
  
  
  MCP Server — GitHub Tools for Agents
&lt;/h2&gt;

&lt;p&gt;Built 6 tools that LangGraph agents will use:&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;GITHUB_TOOLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;get_repo_contents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# list files/folders
&lt;/span&gt;    &lt;span class="n"&gt;get_file_content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# read a file's source code
&lt;/span&gt;    &lt;span class="n"&gt;list_branches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# all branches
&lt;/span&gt;    &lt;span class="n"&gt;get_pr_details&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;# PR changed files (for pr_watcher)
&lt;/span&gt;    &lt;span class="n"&gt;get_repo_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# repo metadata
&lt;/span&gt;    &lt;span class="n"&gt;list_python_files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# recursively find all .py files
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These are &lt;code&gt;@tool&lt;/code&gt; decorated LangChain tools — agents can call them directly in the pipeline.&lt;/p&gt;


&lt;h2&gt;
  
  
  Dev vs Prod Database Setup
&lt;/h2&gt;

&lt;p&gt;One thing I'm proud of: &lt;strong&gt;proper environment parity from day one.&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="c1"&gt;# database.py
&lt;/span&gt;&lt;span class="n"&gt;connect_args&lt;/span&gt; &lt;span class="o"&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;ssl&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;require&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="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATABASE_SSL&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_async_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;connect_args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;connect_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dev  → Docker postgres:16 locally  → DATABASE_SSL=False
Prod → Neon PostgreSQL             → DATABASE_SSL=True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Same code, different config. No hacks.&lt;/p&gt;


&lt;h2&gt;
  
  
  What It Looks Like Running
&lt;/h2&gt;

&lt;p&gt;After &lt;code&gt;uvicorn main:app --reload&lt;/code&gt;, the DB initializes automatically:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;repostatus&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="nb"&gt;ENUM&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;docstatus&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="nb"&gt;ENUM&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;      &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;indexes&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;pipeline_runs&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;Database&lt;/span&gt; &lt;span class="n"&gt;initialized&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Tables&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="n"&gt;Application&lt;/span&gt; &lt;span class="n"&gt;startup&lt;/span&gt; &lt;span class="n"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And Swagger UI at &lt;code&gt;/docs&lt;/code&gt; shows all endpoints live:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxbqhaqg9wo2uatx72bg.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.amazonaws.com%2Fuploads%2Farticles%2Fsxbqhaqg9wo2uatx72bg.png" alt=" " width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Key Learnings from Phase 1 + 2
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Foundation takes time — and that's fine.&lt;/strong&gt;&lt;br&gt;
Two phases before writing a single agent. Every senior engineer says the same thing: boring infrastructure is what separates a demo from a product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Pydantic v2 — use &lt;code&gt;model_config&lt;/code&gt;, not &lt;code&gt;class Config&lt;/code&gt;.&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="c1"&gt;# Wrong (Pydantic v1 style)
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;from_attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="c1"&gt;# Correct (Pydantic v2)
&lt;/span&gt;&lt;span class="n"&gt;model_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConfigDict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_attributes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;3. Never store tokens in plaintext.&lt;/strong&gt;&lt;br&gt;
Fernet encryption, always. Takes 10 minutes to set up, protects your users forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Repository layer is not optional.&lt;/strong&gt;&lt;br&gt;
The moment you have DB queries in your service layer, you've lost. Create a &lt;code&gt;repositories/&lt;/code&gt; folder early, thank yourself later.&lt;/p&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1w9y4wpjx5okh00x7np3.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.amazonaws.com%2Fuploads%2Farticles%2F1w9y4wpjx5okh00x7np3.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What's Next — Part 2
&lt;/h2&gt;

&lt;p&gt;Phase 3 is &lt;strong&gt;LangGraph Core&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;graph/state.py&lt;/code&gt; — the State schema that flows through all agents&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;graph/pipeline.py&lt;/code&gt; — connecting all agents into one graph&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;graph/hitl.py&lt;/code&gt; — the pause/resume HITL checkpoint logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where it gets exciting. The graph will actually start running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Follow the series&lt;/strong&gt; to catch Part 2 when it drops! 🚀&lt;/p&gt;


&lt;h2&gt;
  
  
  GitHub
&lt;/h2&gt;
&lt;h2&gt;
  
  
  &lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Nevin100" rel="noopener noreferrer"&gt;
        Nevin100
      &lt;/a&gt; / &lt;a href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;
        DevdocxAI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      DevDocxAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates engineering documentation by deeply understanding you…DevDocAI is a production-grade multi-agent AI system that automatically generates, maintains, and updates doc. by understanding deeply.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;DevDocxAI 🤖📄&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;DevDocxAi is a production-grade multi-agent LangGraph system that automatically generates and updates engineering documentation from your GitHub codebase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e"&gt;&lt;img src="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e" alt="Python"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069"&gt;&lt;img src="https://camo.githubusercontent.com/9a3024d9f71a2127707cc8c40e5b20188dc57d03f051129b56bee65ca98f7bee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d302e3131352d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/17cf441b5dce665864bd3add5657a7929e00a8209442b67861e9acf237c3c46b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c616e6747726170682d302e322d6f72616e67653f7374796c653d666c61742d737175617265" alt="LangGraph"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c"&gt;&lt;img src="https://camo.githubusercontent.com/c83193d768f5fd708e5ba1a6ec44a81ffb9d0e47094385e6022a1742511452f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f506f737467726553514c2d31362d626c75653f7374796c653d666c61742d737175617265266c6f676f3d706f737467726573716c" alt="PostgreSQL"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/f3cd9467f1a2673efb050d325944267a717320385a6e45da3a19f994f9004339/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f773f7374796c653d666c61742d737175617265" alt="License"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265"&gt;&lt;img src="https://camo.githubusercontent.com/27ee412fbf2ea617f1088ddd749c768146852cea00776460fc2b81837787a6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5374617475732d416374697665253230446576656c6f706d656e742d627269676874677265656e3f7374796c653d666c61742d737175617265" alt="Status"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚨 The Problem:&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Every engineering team has the same dirty secret — &lt;strong&gt;the docs are lying.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not intentionally. Code moves fast, documentation doesn't.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New dev joins → 2 weeks reading outdated wikis&lt;/li&gt;
&lt;li&gt;Senior engineers constantly interrupted with "what does this do?"&lt;/li&gt;
&lt;li&gt;PR gets merged → docs never updated&lt;/li&gt;
&lt;li&gt;Generic RAG chatbots don't understand code &lt;em&gt;structure&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DevDocAI fixes this.&lt;/strong&gt;&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ What It Does&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;🔍 &lt;strong&gt;Connects to your GitHub repo&lt;/strong&gt; via OAuth&lt;/li&gt;
&lt;li&gt;🌳 &lt;strong&gt;Parses your codebase at the AST level&lt;/strong&gt; — understands functions, classes, modules&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Auto-generates structured documentation&lt;/strong&gt; per module and function&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Updates docs on every PR merge&lt;/strong&gt; via GitHub webhooks&lt;/li&gt;
&lt;li&gt;👀 &lt;strong&gt;Human-in-the-Loop review&lt;/strong&gt; — you approve before anything goes live&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Onboarding chatbot&lt;/strong&gt; — new devs ask questions, get answers from live code&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🤖 Agent Pipeline&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;START
  ↓
codebase_parser&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Nevin100/DevdocxAI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;/h2&gt;


&lt;p&gt;&lt;em&gt;Building in public. Part 2 dropping soon.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;python&lt;/code&gt; &lt;code&gt;ai&lt;/code&gt; &lt;code&gt;langchain&lt;/code&gt; &lt;code&gt;productivity&lt;/code&gt; &lt;code&gt;beginners&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>mcp</category>
      <category>langchain</category>
    </item>
    <item>
      <title>I Turned My npm Package Into a Full DevOps Security Toolkit (v2.0.0)</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Fri, 22 May 2026 19:06:33 +0000</pubDate>
      <link>https://dev.to/nevin100/i-turned-my-npm-package-into-a-full-devops-security-toolkit-v200-18lo</link>
      <guid>https://dev.to/nevin100/i-turned-my-npm-package-into-a-full-devops-security-toolkit-v200-18lo</guid>
      <description>&lt;p&gt;A few weeks ago I published dep-inspector-cli — a dependency analyzer for Node.js projects. It went from 107 → 240 weekly downloads in a day, which honestly surprised me.&lt;br&gt;
But the more I used it in real projects, the more I kept thinking: dependency scanning is just one piece. What about secrets, Docker misconfigs, broken CI pipelines?&lt;br&gt;
So I rebuilt it. v2.0.0 is out now — and it's a completely different tool.&lt;/p&gt;

&lt;p&gt;What changed&lt;br&gt;
v1 did one thing: dependency + vulnerability analysis.&lt;br&gt;
v2 does six:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp2mbrw8447timgp615sx.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.amazonaws.com%2Fuploads%2Farticles%2Fp2mbrw8447timgp615sx.png" alt=" " width="499" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The features in detail&lt;br&gt;
🔐 scan:secrets — what it catches&lt;br&gt;
This one I'm most proud of. It scans your entire codebase for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Access Keys &amp;amp; Secret Keys&lt;/li&gt;
&lt;li&gt;OpenAI, Groq, GitHub tokens&lt;/li&gt;
&lt;li&gt;Hardcoded JWT secrets&lt;/li&gt;
&lt;li&gt;MongoDB / PostgreSQL connection strings with credentials&lt;/li&gt;
&lt;li&gt;Stripe &amp;amp; Razorpay live keys (not test keys)&lt;/li&gt;
&lt;li&gt;Generic password= / secret= assignments in source files&lt;/li&gt;
&lt;li&gt;.env files not listed in .gitignore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last one is important — it doesn't scan .env content (that's expected to have secrets), but it checks whether .env is gitignored. A surprising number of projects miss this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dep-inspector scan:secrets

🔐 Secrets Scanner

✅ .env is gitignored
[HIGH] JWT Secret hardcoded
  File : src/middleware/auth.ts:12
  Code : const JWT_SECRET = "my-super-secret-key-123"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🐳 scan:docker — Dockerfile analysis&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dep-inspector scan:docker

🐳 Docker Analysis

[HIGH]   No non-root USER defined — container runs as root
[MEDIUM] No HEALTHCHECK instruction
[MEDIUM] Using ':latest' tag — not reproducible, pin a specific version
[LOW]    npm install without --omit=dev — devDependencies included in image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checks for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container running as root&lt;/li&gt;
&lt;li&gt;Missing HEALTHCHECK&lt;/li&gt;
&lt;li&gt;:latest tag (non-reproducible builds)&lt;/li&gt;
&lt;li&gt;Secrets in ENV/ARG&lt;/li&gt;
&lt;li&gt;Missing .dockerignore&lt;/li&gt;
&lt;li&gt;Single-stage builds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚙️ scan:ci — GitHub Actions linting&lt;br&gt;
This one catches things that are easy to miss in CI configs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dep-inspector scan:ci

⚙️  CI/CD Pipeline Analysis

[HIGH]   deploy.yml: Deprecated '::set-output' — replace with $GITHUB_OUTPUT
[HIGH]   pr.yml: pull_request_target + actions/checkout is a privilege escalation risk
[MEDIUM] build.yml: Actions using @main — pin to a specific version
[LOW]    build.yml: No caching configured — builds will be slow
The pull_request_target + actions/checkout combination is a real security issue that's bitten several open source projects. Good to catch it early.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔌 scan:ports — port monitor&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dep-inspector scan:ports

🔌 Port &amp;amp; Process Monitor

[WARN] :27017 — Port 27017 is publicly exposed — restrict to localhost
[WARN] :6379  — Port 6379 is publicly exposed — restrict to localhost
[OK]   :3000
[OK]   :443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flags database ports (MongoDB, Redis, PostgreSQL, MySQL) that are exposed on 0.0.0.0 instead of localhost. Works on both Linux and Windows.&lt;/p&gt;

&lt;p&gt;📋 scan:logs — logger health&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dep-inspector scan:logs

📋 Logger Health Check

✅ winston detected
⚠️  winston-daily-rotate-file not found — logs may grow unbounded
⚠️  LOG_LEVEL not set in .env — logger may default to verbose in production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Zero AI dependency by default&lt;/strong&gt;&lt;br&gt;
v1 had a problem: if you didn't have GROQ_API_KEY, the tool felt incomplete. Several people mentioned this in feedback.&lt;br&gt;
v2 fixes it properly. Every scan is pure static analysis — regex, file parsing, CLI wrappers. No API calls, no keys, works offline, works in CI.&lt;br&gt;
The --ai flag is additive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Works for everyone&lt;/span&gt;
dep-inspector scan:secrets

&lt;span class="c"&gt;# Optional enhanced output if you have a Groq key&lt;/span&gt;
dep-inspector scan:secrets &lt;span class="nt"&gt;--ai&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also dropped LangChain entirely and moved to the official groq-sdk. Fewer dependencies, no transitive vulnerabilities, faster installs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI/CD integration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;yaml# .github/workflows/security.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security Scan&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dep-inspector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install -g dep-inspector-cli&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dep-inspector scan:secrets --json &amp;gt; secrets.json&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dep-inspector scan:ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;security-reports&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fail build on HIGH severity findings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bashdep-inspector scan:secrets &lt;span class="nt"&gt;--json&lt;/span&gt; | node &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
  let d = '';
  process.stdin.on('data', c =&amp;gt; d += c);
  process.stdin.on('end', () =&amp;gt; {
    const { findings } = JSON.parse(d);
    const high = findings.filter(f =&amp;gt; f.severity === 'HIGH').length;
    if (high &amp;gt; 0) { process.exit(1); }
  });
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's next&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1. .git history scanning (catch secrets that were deleted but still in history)&lt;/li&gt;
&lt;li&gt;2. scan:docker — docker-compose multi-service analysis&lt;/li&gt;
&lt;li&gt;3. --report flag — HTML report with charts&lt;/li&gt;
&lt;li&gt;4. Custom rules via .depinspectorrc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; dep-inspector-cli
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
dep-inspector scan:all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📦 npm: npmjs.com/package/dep-inspector-cli&lt;br&gt;
🐙 GitHub: github.com/Nevin100/Dep-inspector-cli&lt;br&gt;
If it's useful, a ⭐ on GitHub helps a lot. Issues and PRs are open&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devops</category>
      <category>security</category>
      <category>typescript</category>
    </item>
    <item>
      <title>I Built &amp; Published My First npm Package: dep-inspector-cli</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Mon, 20 Apr 2026 16:28:12 +0000</pubDate>
      <link>https://dev.to/nevin100/i-built-published-my-first-npm-package-dep-inspector-cli-13mk</link>
      <guid>https://dev.to/nevin100/i-built-published-my-first-npm-package-dep-inspector-cli-13mk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;And it went from 107 → 240 weekly downloads in a day.!!!!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've been building full-stack apps for a while now — Next.js, TypeScript, PostgreSQL, MongoDB, and much more. But I'd never shipped something to the npm registry before. *&lt;em&gt;dep-inspector-cli *&lt;/em&gt; changed that.&lt;br&gt;
Here's the honest story of what it does, why I built it, and what's coming next.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem:
&lt;/h2&gt;

&lt;p&gt;Every Node.js project eventually runs into this moment:&lt;br&gt;
&lt;code&gt;npm audit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You get a wall of text. Severity levels, CVE IDs, a list of packages - but zero context about which of your actual dependencies pulled the vulnerable one in, or what you should realistically do about it.&lt;br&gt;
I wanted something that actually connected the dots.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution:
&lt;/h2&gt;

&lt;p&gt;What dep-inspector-cli Does&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; dep-inspector-cli
dep-inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it from your project root and you get:&lt;br&gt;
🌳 Visual Dependency Tree — shows your full dep graph with outdated versions flagged inline, not as a separate report.&lt;br&gt;
🛡️ Vulnerability Scan — wraps npm audit but surfaces results with severity, version delta, and a breaking-change warning if the fix is a major bump.&lt;br&gt;
🔗 Dependency Chains — this is the part I care most about. It traces exactly which package in your tree pulled in the vulnerable dep. No more guessing.&lt;br&gt;
📦 Package Context — homepage, author, repo link for flagged packages. Because knowing what a package is matters when you're deciding whether to update or swap it out.&lt;br&gt;
🤖 AI Insights (optional) — add --ai and it uses Groq (llama-3.3-70b) to give you a plain-English breakdown: what the vuln is, what it affects in your specific project, and a recommended fix.&lt;br&gt;
📄 JSON Output — --json flag for CI/CD pipelines. Fail the build if vulnerabilities are found, upload reports as artifacts, the works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Output:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️  Vulnerability Analysis

📦 axios
  Severity   : HIGH
  Version    : 0.21.1 → 1.7.2
  ⚠️  Breaking change possible!
  Repo       : https://github.com/axios/axios
  🔗 Chain: root → axios

💡 Fix Suggestions
  → axios: npm install axios@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CI/CD Integration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check dependencies&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dep-inspector --json &amp;gt; dep-report.json&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload report&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-report&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dep-report.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;I used following tech stack to develop the initial version of this npm package:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript (fully typed)&lt;/li&gt;
&lt;li&gt;Commander.js for CLI parsing&lt;/li&gt;
&lt;li&gt;Chalk + Ora for terminal UX&lt;/li&gt;
&lt;li&gt;LangChain + Groq for the --ai flag&lt;/li&gt;
&lt;li&gt;Semver for version comparison&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Coming Next (v1.2+):
&lt;/h2&gt;

&lt;p&gt;The current version handles vulnerability scanning well, but I want dep-inspector to be genuinely useful for production-grade projects too. Here's what I'm actively working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;🏥 Dependency Health Scoring - an overall health score for your project's dependency tree. Factors: vulnerability count, how outdated your deps are, and whether maintainers are active. One number that tells you roughly how much debt you're carrying.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;📊 Production Package Support - first-class analysis for packages like winston, pino, morgan (logging), helmet, cors, express-rate-limit (security middleware), dotenv, zod (config/validation). Currently, these show up in the tree, but there's no opinionated analysis. Coming soon: known best-practice checks and upgrade guidance specific to each ecosystem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🔍 License Audit - flag packages with restrictive licenses (GPL, AGPL) that might be a problem in commercial projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;📈 Trend Tracking — run dep-inspector over time and see if your health score is improving or regressing. Useful for teams that do regular dependency maintenance sprints.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It and can raise an issue and some suggestions in the comments:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; dep-inspector-cli
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
dep-inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;📦 npm: npmjs.com/package/dep-inspector-cli&lt;/li&gt;
&lt;li&gt;🐙 GitHub: &lt;a href="https://github.com/Nevin100/Dep-inspector-cli" rel="noopener noreferrer"&gt;https://github.com/Nevin100/Dep-inspector-cli&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If it's useful, a ⭐ on GitHub goes a long way. And if you run into issues or have feature requests — PRs are open.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyk4h7f5wwmreosodln5.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.amazonaws.com%2Fuploads%2Farticles%2Fzyk4h7f5wwmreosodln5.png" alt="Main Package Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa3hys75b4y2si8y1loe.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.amazonaws.com%2Fuploads%2Farticles%2Ffa3hys75b4y2si8y1loe.png" alt="A Description of Usage of the tool on npm official platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7sxg03tmijwb5cs99kb.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.amazonaws.com%2Fuploads%2Farticles%2Fv7sxg03tmijwb5cs99kb.png" alt="Usage and Commands"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>node</category>
      <category>devtools</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Revision and completing Nextronix.ai</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Tue, 06 May 2025 17:54:21 +0000</pubDate>
      <link>https://dev.to/nevin100/revision-and-completing-nextronixai-261o</link>
      <guid>https://dev.to/nevin100/revision-and-completing-nextronixai-261o</guid>
      <description>&lt;p&gt;Just did revision of nextjs while completing the nextronix.ai Project.&lt;/p&gt;

&lt;h1&gt;
  
  
  Day 4 of coding and learning!!!
&lt;/h1&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>ai</category>
    </item>
    <item>
      <title>Nextronix.ai on the verge of complete!!</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Mon, 05 May 2025 16:23:06 +0000</pubDate>
      <link>https://dev.to/nevin100/nextronixai-on-the-verge-of-complete-559g</link>
      <guid>https://dev.to/nevin100/nextronixai-on-the-verge-of-complete-559g</guid>
      <description></description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>ai</category>
    </item>
    <item>
      <title>Nextronix Diet: Forks Over Fail</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Sat, 03 May 2025 18:10:32 +0000</pubDate>
      <link>https://dev.to/nevin100/nextronix-diet-forks-over-fail-2pp5</link>
      <guid>https://dev.to/nevin100/nextronix-diet-forks-over-fail-2pp5</guid>
      <description>&lt;p&gt;Welcome to &lt;strong&gt;Nextronix.ai&lt;/strong&gt; — my AI-powered fitness diet planner, built as part of my journey to master full-stack development and AI integration! Powered by &lt;strong&gt;Gemini API, Vapi Voice Assistant, and crafted using Next.js, TypeScript, Convex DB, and Clerk&lt;/strong&gt;, this project listens to your voice, gathers key details, and creates a free, personalized diet plan just for you.&lt;/p&gt;

&lt;p&gt;🔹 AI Voice Assistant Calls (via Vapi)&lt;br&gt;
🔹 Info gathering through natural conversation&lt;br&gt;
🔹 Personalized fitness diet plan&lt;br&gt;
🔹 Real-time database with Convex&lt;br&gt;
🔹 Auth handled by Clerk&lt;br&gt;
🔹 Built for learning, sharing, and consistency&lt;/p&gt;

&lt;p&gt;Learning from the tutorial on Youtube: Codesistency&lt;/p&gt;

&lt;p&gt;This is Day 2 (missed Day 1 😅), but I’m showing up consistently from here on!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Insightful Article Post</title>
      <dc:creator>Nevin-Bali100</dc:creator>
      <pubDate>Tue, 13 Aug 2024 18:17:39 +0000</pubDate>
      <link>https://dev.to/nevin100/insightful-article-post-op9</link>
      <guid>https://dev.to/nevin100/insightful-article-post-op9</guid>
      <description>&lt;p&gt;I read this post on the dev.daily about the good and bad commit changes on the git which I found quite insightful.&lt;br&gt;
It was able to draw some important conclusions regarding the approach of doing proper commits but also I would like to add my perspective that for some scenarios,one can stash their current changes and can move to higher branch.&lt;/p&gt;

&lt;p&gt;post link : &lt;a href="https://dev.to/sheraz4194/good-commit-vs-bad-commit-best-practices-for-git-1plc"&gt;https://dev.to/sheraz4194/good-commit-vs-bad-commit-best-practices-for-git-1plc&lt;/a&gt;&lt;br&gt;
credits: Sheraz Manzoor &lt;/p&gt;

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