<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nitesh More</title>
    <description>The latest articles on Forem by Nitesh More (@nitz22199).</description>
    <link>https://forem.com/nitz22199</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3438204%2Fbce55edf-e60c-48f6-be61-e2f7a23cab23.jpg</url>
      <title>Forem: Nitesh More</title>
      <link>https://forem.com/nitz22199</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nitz22199"/>
    <language>en</language>
    <item>
      <title>AWS Networking Demystified: VPC, Subnets, Security, and Beyond</title>
      <dc:creator>Nitesh More</dc:creator>
      <pubDate>Fri, 22 Aug 2025 05:44:59 +0000</pubDate>
      <link>https://forem.com/nitz22199/aws-networking-demystified-vpc-subnets-security-and-beyond-3jcn</link>
      <guid>https://forem.com/nitz22199/aws-networking-demystified-vpc-subnets-security-and-beyond-3jcn</guid>
      <description>&lt;p&gt;When you first dive into AWS, networking feels like a maze. Between &lt;strong&gt;VPCs, subnets, routing tables, security groups, and NACLs&lt;/strong&gt;, it’s easy to get lost.&lt;/p&gt;

&lt;p&gt;This guide breaks it down step by step, so you’ll walk away knowing how all the pieces fit together.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Virtual Private Cloud (VPC)
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;VPC&lt;/strong&gt; is your own private section of the AWS cloud.&lt;br&gt;
Think of it as your &lt;strong&gt;own data center in the cloud&lt;/strong&gt;, isolated from others.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You define the IP address range (CIDR block, e.g., &lt;code&gt;10.0.0.0/16&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Inside it, you place subnets, route tables, and security rules.&lt;/li&gt;
&lt;li&gt;You can connect your VPC to the internet (via &lt;strong&gt;Internet Gateway&lt;/strong&gt;) or keep it private.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Every AWS account comes with a &lt;strong&gt;default VPC&lt;/strong&gt;, but for production, you almost always create custom ones.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Subnets
&lt;/h2&gt;

&lt;p&gt;Inside a VPC, you slice the network into &lt;strong&gt;subnets&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public subnet&lt;/strong&gt; → connected to the internet via an Internet Gateway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private subnet&lt;/strong&gt; → no direct internet access, usually behind a NAT Gateway or used for internal services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📝 Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public subnet hosts a web server.&lt;/li&gt;
&lt;li&gt;Private subnet hosts a database (never exposed directly to the internet).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Route Tables
&lt;/h2&gt;

&lt;p&gt;Subnets don’t know where to send traffic by default. That’s where &lt;strong&gt;Route Tables&lt;/strong&gt; come in.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each subnet is associated with a route table.&lt;/li&gt;
&lt;li&gt;Example route: &lt;code&gt;0.0.0.0/0 → Internet Gateway&lt;/code&gt; (for internet access).&lt;/li&gt;
&lt;li&gt;Private subnets may instead route &lt;code&gt;0.0.0.0/0 → NAT Gateway&lt;/code&gt; (so they can access the internet &lt;em&gt;outbound&lt;/em&gt; but remain unreachable from outside).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Internet Gateway (IGW) &amp;amp; NAT Gateway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Internet Gateway (IGW)&lt;/strong&gt; → attaches to a VPC to allow resources in public subnets to connect to the internet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NAT Gateway&lt;/strong&gt; → allows private subnets to initiate outbound traffic to the internet (like downloading updates) while blocking inbound traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Rule of thumb:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public subnet = IGW.&lt;/li&gt;
&lt;li&gt;Private subnet = NAT Gateway.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Security Groups (SG)
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Security Group&lt;/strong&gt; is like a &lt;strong&gt;firewall at the instance level&lt;/strong&gt; (EC2, RDS, etc).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stateful&lt;/strong&gt;: If you allow inbound traffic, the response is automatically allowed.&lt;/li&gt;
&lt;li&gt;Works on &lt;strong&gt;allow rules only&lt;/strong&gt; (no explicit deny).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow inbound &lt;code&gt;TCP 22&lt;/code&gt; (SSH) from &lt;code&gt;10.0.0.0/16&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Allow inbound &lt;code&gt;TCP 443&lt;/code&gt; (HTTPS) from anywhere.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Network ACLs (NACLs)
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;NACL&lt;/strong&gt; is like a &lt;strong&gt;firewall at the subnet level&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stateless&lt;/strong&gt;: You must define both inbound and outbound rules.&lt;/li&gt;
&lt;li&gt;Works with &lt;strong&gt;allow and deny rules&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deny inbound &lt;code&gt;TCP 22&lt;/code&gt; (SSH) from everywhere.&lt;/li&gt;
&lt;li&gt;Allow inbound &lt;code&gt;TCP 443&lt;/code&gt; (HTTPS) from &lt;code&gt;0.0.0.0/0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;👉 Quick comparison:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security Groups = “Who can talk to this server?”&lt;/li&gt;
&lt;li&gt;NACLs = “What traffic can pass through this subnet?”&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. VPC Peering
&lt;/h2&gt;

&lt;p&gt;What if you have two VPCs and want them to talk?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPC Peering&lt;/strong&gt; connects two VPCs privately using AWS backbone network.&lt;/li&gt;
&lt;li&gt;It’s &lt;strong&gt;one-to-one&lt;/strong&gt; and doesn’t support transitive peering (VPC A can’t automatically talk to C via B).&lt;/li&gt;
&lt;li&gt;Alternative for larger architectures → &lt;strong&gt;Transit Gateway&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8. Transit Gateway (TGW)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Transit Gateway&lt;/strong&gt; is like a &lt;strong&gt;hub for multiple VPCs and on-prem networks&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Instead of managing many VPC peerings, you connect each VPC to TGW once.&lt;/li&gt;
&lt;li&gt;Supports transitive routing.&lt;/li&gt;
&lt;li&gt;Great for enterprise-scale multi-VPC setups.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. PrivateLink &amp;amp; VPC Endpoints
&lt;/h2&gt;

&lt;p&gt;Sometimes you don’t want your private subnet to talk to AWS services (like S3, DynamoDB) over the public internet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPC Endpoint (Gateway/Interface)&lt;/strong&gt; → private connection between your VPC and AWS service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PrivateLink&lt;/strong&gt; → lets you securely connect to services &lt;em&gt;in another VPC&lt;/em&gt; without exposing traffic to the internet.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  10. Putting It All Together (Example)
&lt;/h2&gt;

&lt;p&gt;Imagine a simple 3-tier architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public Subnet&lt;/strong&gt; → Load Balancer (ALB)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private Subnet A&lt;/strong&gt; → App Servers (EC2 in Auto Scaling Group)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private Subnet B&lt;/strong&gt; → Database (RDS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Traffic flow:&lt;br&gt;
&lt;code&gt;User → ALB (Public Subnet) → App Server (Private Subnet) → Database (Private Subnet)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Security Layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ALB SG → allows inbound HTTPS from internet.&lt;/li&gt;
&lt;li&gt;App Server SG → allows inbound only from ALB SG.&lt;/li&gt;
&lt;li&gt;DB SG → allows inbound only from App Server SG.&lt;/li&gt;
&lt;li&gt;NACLs → add subnet-wide restrictions for extra defense.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  11. Key Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;least privilege&lt;/strong&gt; rules (narrow CIDR ranges).&lt;/li&gt;
&lt;li&gt;Split workloads across &lt;strong&gt;AZs&lt;/strong&gt; for resilience.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;NAT Gateway&lt;/strong&gt; for private subnets needing outbound access.&lt;/li&gt;
&lt;li&gt;For many VPCs, prefer &lt;strong&gt;Transit Gateway&lt;/strong&gt; over complex peering meshes.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;VPC Flow Logs&lt;/strong&gt; to monitor traffic.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Takeaway
&lt;/h2&gt;

&lt;p&gt;AWS networking isn’t just about connecting resources — it’s about &lt;strong&gt;designing secure, scalable, and maintainable networks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you understand &lt;strong&gt;VPC, subnets, routing, security groups, NACLs, and peering&lt;/strong&gt;, you’ve got the foundation to handle real-world AWS architectures.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>networking</category>
      <category>cloudcomputing</category>
      <category>devops</category>
    </item>
    <item>
      <title>Into the Future: What is Agentic AI (and How You Can Try It Today?)</title>
      <dc:creator>Nitesh More</dc:creator>
      <pubDate>Tue, 19 Aug 2025 22:57:02 +0000</pubDate>
      <link>https://forem.com/nitz22199/into-the-future-what-is-agentic-ai-and-how-you-can-try-it-today-4jm9</link>
      <guid>https://forem.com/nitz22199/into-the-future-what-is-agentic-ai-and-how-you-can-try-it-today-4jm9</guid>
      <description>&lt;h3&gt;
  
  
  1. What is Agentic AI?
&lt;/h3&gt;

&lt;p&gt;Agentic AI goes beyond chatbots. Instead of waiting for you to type prompts, agents act &lt;strong&gt;proactively and independently&lt;/strong&gt;. They:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plan tasks&lt;/li&gt;
&lt;li&gt;Call APIs and use tools&lt;/li&gt;
&lt;li&gt;Adapt to new information&lt;/li&gt;
&lt;li&gt;Automate workflows (like triaging tickets, deploying code, or managing data pipelines)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as moving from “ask me something” to “I’ll get it done.”&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%2Fikuy5b4bihso0kg9xh15.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%2Fikuy5b4bihso0kg9xh15.png" alt="AI" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Why It Matters
&lt;/h3&gt;

&lt;p&gt;Traditional AI = reactive.&lt;br&gt;
Agentic AI = &lt;strong&gt;autonomous + adaptive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This opens the door for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers automating repetitive DevOps tasks.&lt;/li&gt;
&lt;li&gt;Businesses streamlining support, ticketing, and triage.&lt;/li&gt;
&lt;li&gt;Knowledge workers offloading research, writing, and analysis.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  3. Building Your First Agent (Hands-On)
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Build a Free, Open-Source Agent: GitHub Issue Triage with Ollama
&lt;/h3&gt;
&lt;h3&gt;
  
  
  What you’ll build
&lt;/h3&gt;

&lt;p&gt;A small Python agent that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads open GitHub issues&lt;/li&gt;
&lt;li&gt;Thinks locally via an &lt;strong&gt;open-source LLM&lt;/strong&gt; (Ollama)&lt;/li&gt;
&lt;li&gt;Decides labels (bug/feature/docs/etc.)&lt;/li&gt;
&lt;li&gt;Applies labels via the GitHub API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No cloud LLM keys required.&lt;/p&gt;


&lt;h2&gt;
  
  
  Prereqs (all free)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Python 3.10+&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ollama&lt;/strong&gt; (local LLM runtime)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Install: &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;https://ollama.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start Ollama server (if it isn’t already):&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt; ollama serve
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Pull a small instruct model (pick one):&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt; ollama pull llama3.1:8b-instruct-q2_K
 &lt;span class="c"&gt;# or smaller options if RAM is tight:&lt;/span&gt;
 &lt;span class="c"&gt;# ollama pull qwen2.5:1.5b-instruct&lt;/span&gt;
 &lt;span class="c"&gt;# ollama pull phi3:mini&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Verify the server &amp;amp; model&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt; curl http://localhost:11434/api/tags
 &lt;span class="c"&gt;# expect: {"models":[{"name":"llama3.1:8b-instruct-q2_K", ...}]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;




&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Personal Access Token&lt;/strong&gt; (classic or fine-grained) with &lt;code&gt;repo&lt;/code&gt; scope&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Save it to an env var: &lt;code&gt;export GITHUB_TOKEN=ghp_...&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Project layout
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent/
  triage_agent.py
  tools.py
  prompts.py
  requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  requirements.txt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;requests&amp;gt;=2.31.0
pydantic&amp;gt;=2.7.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 1: Define “tools” (GitHub API helpers)
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;tools.py&lt;/code&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;

&lt;span class="n"&gt;GITHUB_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&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_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;REPO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPO&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="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;REPO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Set REPO env var, e.g. export REPO=owner/repo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;HEADERS&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;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept&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;application/vnd.github+json&lt;/span&gt;&lt;span class="sh"&gt;"&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;get_open_issues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.github.com/repos/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;REPO&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/issues?state=open&amp;amp;per_page=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# Filter out PRs (GitHub returns PRs in /issues)
&lt;/span&gt;    &lt;span class="n"&gt;issues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pull_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# Keep only fields we need
&lt;/span&gt;    &lt;span class="n"&gt;simplified&lt;/span&gt; &lt;span class="o"&gt;=&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;number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number&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;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&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;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;issues&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;simplified&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issue_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&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="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;labels&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.github.com/repos/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;REPO&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/issues/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;issue_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/labels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&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;labels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Labels applied to issue #&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;issue_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: A clear system prompt for the model
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;prompts.py&lt;/code&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="n"&gt;ALLOWED_LABELS&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;bug&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;feature&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;enhancement&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;docs&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;question&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;performance&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;refactor&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;security&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a GitHub issue triage agent.

Return ONLY a JSON array. No prose, no markdown, no code fences.

Allowed labels (use up to two):
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ALLOWED_LABELS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

For each issue object in the input, produce an object:
{{
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &amp;lt;issue_number&amp;gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;labels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: [&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bug&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;] // labels MUST be from the allowed list
}}

If you are unsure, use one generic label: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enhancement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.
If you cannot determine labels, return an empty array [].

Output format examples:
[
  {{ &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: 123, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;labels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: [&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bug&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;] }},
  {{ &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: 456, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;labels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: [&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enhancement&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;] }}
]
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Minimal agent loop using Ollama’s local API
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;triage_agent.py&lt;/code&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_open_issues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;add_labels&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;prompts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ALLOWED_LABELS&lt;/span&gt;

&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MODEL&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;llama3.1:8b-instruct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;OLLAMA_BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OLLAMA_BASE&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;http://localhost:11434&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;OLLAMA_BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/api/generate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DEBUG&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;1&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;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&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;DEBUG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&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;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_json_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&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="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# Try to extract first JSON array (handles stray prose)
&lt;/span&gt;    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rfind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&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;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="k"&gt;return&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;ask_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
    &lt;span class="n"&gt;user_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Issues:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&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="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;payload&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;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;options&lt;/span&gt;&lt;span class="sh"&gt;"&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;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;dprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] POST &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (model=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&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;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;dprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] LLM status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;dprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Raw model reply (first 500 chars):&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;dprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_json_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;dprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Parsed suggestions: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sanitize_labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&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="n"&gt;List&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;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;labels&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;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ALLOWED_LABELS&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REPO&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="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR: Set REPO env var, e.g. export REPO=owner/repo&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Using repo: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;issues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_open_issues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Open issues (non-PR): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] No open issues found. Create one and rerun.&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="n"&gt;suggestions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ask_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;suggestions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Model returned no suggestions or parsing failed.&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="n"&gt;any_applied&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;suggestions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;raw_labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;labels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
        &lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sanitize_labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_labels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Suggestion → issue #&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: raw=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;raw_labels&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; filtered=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Guardrail: never auto-apply "security"
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;security&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;security&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;num&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;any_applied&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Applying &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to issue #&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;add_labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Failed to apply labels to #&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;any_applied&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[agent] Nothing to apply (no labels or numbers).&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;owner/repo
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ghp_yourtoken
&lt;span class="c"&gt;# (optional) pick a smaller model if needed&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;llama3.1:8b-instruct-q2_K  

python triage_agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see it print which labels it applied. Open an issue with “crash, error, stacktrace” and watch it label &lt;code&gt;bug&lt;/code&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%2Fvsfwtni6ktvj2132gtnv.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%2Fvsfwtni6ktvj2132gtnv.png" alt="Console Image" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&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%2Fkk62kxe5fiy63u0rdk3t.png" alt="label added" width="800" height="275"&gt;
&lt;/h2&gt;




&lt;h2&gt;
  
  
  How this is “agentic”
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The model &lt;strong&gt;reasons&lt;/strong&gt; over multiple issues and decides actions (labels).&lt;/li&gt;
&lt;li&gt;The Python loop &lt;strong&gt;executes tools&lt;/strong&gt; (GitHub API) based on those decisions.&lt;/li&gt;
&lt;li&gt;You can add &lt;strong&gt;reflection&lt;/strong&gt; (e.g., if labels empty, re-ask with a hint), &lt;strong&gt;memory&lt;/strong&gt; (store past choices in a JSON file), and &lt;strong&gt;approval gates&lt;/strong&gt; (dry run mode).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Real-World Ecosystem: Where Claude Fits In
&lt;/h3&gt;

&lt;p&gt;Now that you understand the basics, here’s where things get exciting:&lt;/p&gt;

&lt;p&gt;🟣 &lt;strong&gt;Anthropic’s Claude Agents&lt;/strong&gt;&lt;br&gt;
Anthropic recently launched &lt;a href="https://www.anthropic.com/solutions/agents" rel="noopener noreferrer"&gt;Claude Agents&lt;/a&gt;. These are production-ready frameworks for building &lt;strong&gt;safe, reliable, long-context AI agents&lt;/strong&gt;. They integrate with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude API&lt;/strong&gt; – the core brain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workbench&lt;/strong&gt; – an environment for prototyping and testing agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; – a way for agents to connect to external tools and APIs safely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essentially, Claude is positioning itself as the &lt;strong&gt;enterprise-grade agentic AI platform&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔵 &lt;strong&gt;Other Ecosystem Players&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI:&lt;/strong&gt; AutoGPT, GPTs, and upcoming agent frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LangChain &amp;amp; LlamaIndex:&lt;/strong&gt; Open-source toolkits for chaining agent logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startups (e.g., Cognition’s Devin, Cursor):&lt;/strong&gt; Agents for specific verticals like coding.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  5. Debugging the Hype: Gotchas to Watch Out For
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Agents aren’t perfect — they can still hallucinate or make bad decisions.&lt;/li&gt;
&lt;li&gt;Cost can grow if you let an agent loop endlessly.&lt;/li&gt;
&lt;li&gt;Security matters — don’t give agents unrestricted API keys.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  6. The Future
&lt;/h3&gt;

&lt;p&gt;The real magic will come when agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Collaborate with each other&lt;/strong&gt; (multi-agent systems).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stay persistent&lt;/strong&gt; (remember context across weeks).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Work seamlessly with human approval loops&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re at the early days, but just like cloud and Kubernetes once felt futuristic, agentic AI will soon feel normal.&lt;/p&gt;




</description>
      <category>anthropic</category>
      <category>agenticai</category>
      <category>ollama</category>
      <category>opensourceai</category>
    </item>
    <item>
      <title>Pods, ReplicaSets, Deployments, and StatefulSets: What’s the Difference?</title>
      <dc:creator>Nitesh More</dc:creator>
      <pubDate>Tue, 19 Aug 2025 04:02:09 +0000</pubDate>
      <link>https://forem.com/nitz22199/pods-replicasets-deployments-and-statefulsets-whats-the-difference-4f2n</link>
      <guid>https://forem.com/nitz22199/pods-replicasets-deployments-and-statefulsets-whats-the-difference-4f2n</guid>
      <description>&lt;p&gt;When I started with Kubernetes, one of the most confusing things was figuring out &lt;strong&gt;why there are so many different objects&lt;/strong&gt; just to run a container. I thought, “Why can’t I just run my app as a Pod and be done with it?”&lt;/p&gt;

&lt;p&gt;Turns out, Pods are just the beginning. As you scale, update, and manage real-world apps, you’ll need ReplicaSets, Deployments, and sometimes StatefulSets. Let’s walk through each one in plain English.&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%2Food2fqxbkpxl7avmn9ux.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%2Food2fqxbkpxl7avmn9ux.png" alt="pod" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🟦 Pod: The Basic Building Block
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Pod&lt;/strong&gt; is the smallest thing you can run in Kubernetes. It usually holds one container, sometimes more if they’re tightly coupled (like a sidecar).&lt;/p&gt;

&lt;p&gt;Think of a Pod as a &lt;strong&gt;little wrapper&lt;/strong&gt; around your app. It gives it an IP address, some storage, and a place to live inside the cluster.&lt;/p&gt;

&lt;p&gt;The catch? Pods are &lt;strong&gt;ephemeral&lt;/strong&gt;. If one dies, it’s gone. Kubernetes won’t automatically bring it back unless you add another layer on top.&lt;/p&gt;

&lt;p&gt;👉 Example Pod:&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&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;nginx-pod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&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;nginx&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great for testing. Not so great for production.&lt;/p&gt;




&lt;h2&gt;
  
  
  🟧 ReplicaSet: Keeping Things Alive
&lt;/h2&gt;

&lt;p&gt;That’s where a &lt;strong&gt;ReplicaSet&lt;/strong&gt; comes in. Imagine you want three Pods running at all times. If one crashes, the ReplicaSet creates a new one.&lt;/p&gt;

&lt;p&gt;It’s like a &lt;strong&gt;babysitter for Pods&lt;/strong&gt; — making sure the right number are always running.&lt;/p&gt;

&lt;p&gt;👉 Example:&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ReplicaSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&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;nginx-rs&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&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;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Still, ReplicaSets are rarely used directly. We usually let Deployments handle them.&lt;/p&gt;




&lt;h2&gt;
  
  
  🟨 Deployment: The Real Hero
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Deployment&lt;/strong&gt; is what you’ll use most of the time. It manages ReplicaSets for you and makes rolling updates painless.&lt;/p&gt;

&lt;p&gt;Say you want to update your app to a new version. With a Deployment, Kubernetes replaces Pods &lt;strong&gt;one by one&lt;/strong&gt;, so your service never goes down. And if something breaks, you can roll back instantly.&lt;/p&gt;

&lt;p&gt;👉 Example Deployment:&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&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;nginx-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&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;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.25&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the bread and butter for running web apps, APIs, or really any &lt;strong&gt;stateless service&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🟩 StatefulSet: For Apps That Remember Things
&lt;/h2&gt;

&lt;p&gt;Finally, there’s the &lt;strong&gt;StatefulSet&lt;/strong&gt;. This one is special. While Deployments treat Pods as disposable, StatefulSets give each Pod a &lt;strong&gt;stable identity&lt;/strong&gt; — along with its own persistent storage.&lt;/p&gt;

&lt;p&gt;This is exactly what you need for databases, queues, or anything that can’t just “forget” its data when restarted.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pods get predictable names (&lt;code&gt;db-0&lt;/code&gt;, &lt;code&gt;db-1&lt;/code&gt;, &lt;code&gt;db-2&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Each Pod can have its &lt;strong&gt;own volume&lt;/strong&gt; that sticks around even if the Pod is deleted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Example StatefulSet:&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="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StatefulSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&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;web&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;serviceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nginx"&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&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;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:latest&lt;/span&gt;
  &lt;span class="na"&gt;volumeClaimTemplates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;metadata&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;www&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ReadWriteOnce"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now each Pod (&lt;code&gt;web-0&lt;/code&gt;, &lt;code&gt;web-1&lt;/code&gt;) has its own storage that won’t get mixed up.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Wrapping It Up
&lt;/h2&gt;

&lt;p&gt;Here’s how I like to remember it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pod&lt;/strong&gt; → Just runs your container. Great for testing, not production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ReplicaSet&lt;/strong&gt; → Babysits Pods, keeps the right number running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt; → The real workhorse. Handles updates and rollbacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;StatefulSet&lt;/strong&gt; → For stateful apps like databases that need stable IDs and storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re starting out, you’ll almost always use &lt;strong&gt;Deployments&lt;/strong&gt;. When you need databases or apps that care about persistence, that’s when you bring in &lt;strong&gt;StatefulSets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Everything else (Pods, ReplicaSets) are still there under the hood, but you don’t usually manage them directly.&lt;/p&gt;




&lt;p&gt;👉 Next time you see &lt;code&gt;kubectl get all&lt;/code&gt; showing Pods, ReplicaSets, Deployments, and maybe a StatefulSet, you’ll know exactly what role each one plays.&lt;/p&gt;




</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>cka</category>
      <category>ckad</category>
    </item>
    <item>
      <title>Automating DNS with ExternalDNS on EKS and Istio: Lessons From Real-World Gotchas</title>
      <dc:creator>Nitesh More</dc:creator>
      <pubDate>Sun, 17 Aug 2025 02:58:53 +0000</pubDate>
      <link>https://forem.com/nitz22199/automating-dns-with-externaldns-on-eks-and-istio-lessons-from-real-world-gotchas-12fa</link>
      <guid>https://forem.com/nitz22199/automating-dns-with-externaldns-on-eks-and-istio-lessons-from-real-world-gotchas-12fa</guid>
      <description>&lt;p&gt;When I first set up Istio on Amazon EKS, I thought DNS automation would be the easy part. Just install ExternalDNS, connect it to Route 53, and boom — &lt;code&gt;api.yourdomain.com&lt;/code&gt; and &lt;code&gt;grafana.yourdomain.com&lt;/code&gt; should resolve to my cluster.&lt;/p&gt;

&lt;p&gt;Most of it did work smoothly. The EKS add-on installed fine, IAM permissions were clear from the docs, and Route 53 was wired up. But there was &lt;strong&gt;one thing missing in the documentation that cost me a lot of time&lt;/strong&gt;: how to make ExternalDNS notice Istio hostnames.&lt;/p&gt;

&lt;p&gt;In this post, I’ll explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How ExternalDNS, cert-manager, and Istio fit together&lt;/li&gt;
&lt;li&gt;The exact setup I used&lt;/li&gt;
&lt;li&gt;The one gotcha that slowed me down (annotations!)&lt;/li&gt;
&lt;li&gt;A debugging checklist you can use when DNS records don’t appear&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 The Basics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔹 &lt;a href="https://kubernetes-sigs.github.io/external-dns/v0.12.0/" rel="noopener noreferrer"&gt;ExternalDNS&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A Kubernetes controller that &lt;strong&gt;creates and updates DNS records&lt;/strong&gt; automatically in providers like Route 53. Annotate a Service or Ingress with a hostname, and ExternalDNS will manage the record for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔹 &lt;a href="https://cert-manager.io/docs/" rel="noopener noreferrer"&gt;cert-manager&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;cert-manager is a Kubernetes add-on that automates the management of TLS certificates. It integrates with Let’s Encrypt, Vault, or private CAs to issue and renew certificates automatically.&lt;/p&gt;

&lt;p&gt;At its core, cert-manager uses two main components:&lt;/p&gt;

&lt;p&gt;Issuer/ClusterIssuer → defines where certificates are requested from (e.g., Let’s Encrypt).&lt;/p&gt;

&lt;p&gt;Certificate → defines what domain you want the cert for (e.g., *.yourdomain.com).&lt;/p&gt;

&lt;p&gt;In my setup, I used it with a wildcard certificate (&lt;code&gt;*.yourdomain.com&lt;/code&gt;) from Let’s Encrypt so all subdomains were automatically covered. &lt;/p&gt;

&lt;h3&gt;
  
  
  🔹 &lt;a href="https://istio.io/latest/docs/" rel="noopener noreferrer"&gt;Istio&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A service mesh that adds traffic routing and security. The &lt;strong&gt;Istio Gateway&lt;/strong&gt; terminates TLS and forwards traffic based on the requested host (&lt;code&gt;api.yourdomain.com&lt;/code&gt;, &lt;code&gt;grafana.yourdomain.com&lt;/code&gt;, etc.).&lt;/p&gt;




&lt;h2&gt;
  
  
  📐 Architecture
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EKS cluster&lt;/strong&gt; with Istio installed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Istio ingressgateway&lt;/strong&gt; (type LoadBalancer) → backed by an AWS NLB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ExternalDNS EKS add-on&lt;/strong&gt; → manages Route 53 records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Route 53 hosted zone&lt;/strong&gt; for &lt;code&gt;yourdomain.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cert-manager&lt;/strong&gt; → wildcard TLS cert&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VirtualServices&lt;/strong&gt; → route subdomains to the right service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flow:&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%2Fbop1aw4uixy2dcs5jdlm.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%2Fbop1aw4uixy2dcs5jdlm.png" alt="Flow diagram" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Install ExternalDNS Add-On
&lt;/h3&gt;

&lt;p&gt;With EKS it’s easier to use the managed add-on. Example config:&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="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
&lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;upsert-only&lt;/span&gt;
&lt;span class="na"&gt;txtOwnerId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;archops&lt;/span&gt;
&lt;span class="na"&gt;domainFilters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;yourdomain.com&lt;/span&gt;
&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;service&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;istio-gateway&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Annotate the Istio IngressGateway
&lt;/h3&gt;

&lt;p&gt;This was the missing piece. ExternalDNS does not see Istio VirtualServices directly. You need to &lt;strong&gt;annotate the Istio ingressgateway Service&lt;/strong&gt; with the subdomains you want managed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; istio-system annotate svc istio-ingressgateway &lt;span class="se"&gt;\&lt;/span&gt;
  external-dns.alpha.kubernetes.io/hostname&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"api.yourdomain.com,grafana.yourdomain.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--overwrite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once I did this, ExternalDNS created the records in Route 53 instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Istio Gateway + VirtualServices
&lt;/h3&gt;

&lt;p&gt;After ExternalDNS creates the DNS records, Istio takes over to handle &lt;strong&gt;TLS termination&lt;/strong&gt; and &lt;strong&gt;routing based on host headers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;First, you need a &lt;code&gt;Gateway&lt;/code&gt; that uses the wildcard TLS certificate from cert-manager. Then you create separate &lt;code&gt;VirtualService&lt;/code&gt; objects for each subdomain.&lt;/p&gt;

&lt;h4&gt;
  
  
  Gateway with Wildcard Certificate
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.istio.io/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Gateway&lt;/span&gt;
&lt;span class="na"&gt;metadata&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;my-gateway&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;istio-system&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;istio&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingressgateway&lt;/span&gt;    &lt;span class="c1"&gt;# use istio’s default ingress gateway&lt;/span&gt;
  &lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&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;https&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPS&lt;/span&gt;
    &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SIMPLE&lt;/span&gt;
      &lt;span class="na"&gt;credentialName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wildcard-yourdomain-com&lt;/span&gt;   &lt;span class="c1"&gt;# cert-manager Secret&lt;/span&gt;
    &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.yourdomain.com&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;grafana.yourdomain.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  VirtualService for API
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.istio.io/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VirtualService&lt;/span&gt;
&lt;span class="na"&gt;metadata&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;api-vs&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.yourdomain.com&lt;/span&gt;
  &lt;span class="na"&gt;gateways&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;istio-system/my-gateway&lt;/span&gt;
  &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-svc.api.svc.cluster.local&lt;/span&gt;
        &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and similar VirtualService for Grafana just change host, service name and port.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚧 The Gotcha: Annotations
&lt;/h2&gt;

&lt;p&gt;Everything else was well-documented, but this part wasn’t obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ExternalDNS doesn’t read Istio VirtualServices&lt;/li&gt;
&lt;li&gt;Without annotations, no DNS records get created&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;external-dns.alpha.kubernetes.io/hostname&lt;/code&gt; to the &lt;strong&gt;ingressgateway Service&lt;/strong&gt; solved it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was the one real stumbling block for me.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Debugging Checklist
&lt;/h2&gt;

&lt;p&gt;If your DNS records don’t show up, here’s what to check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Logs&lt;/strong&gt;&lt;br&gt;
check logs using &lt;code&gt;kubectl logs deploy/external-dns -n kube-system&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Domain filter&lt;/strong&gt;&lt;br&gt;
Make sure &lt;code&gt;domainFilter&lt;/code&gt; matches your hosted zone exactly (&lt;code&gt;yourdomain.com&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IAM permissions&lt;/strong&gt;&lt;br&gt;
ExternalDNS service account needs &lt;code&gt;ChangeResourceRecordSets&lt;/code&gt; and &lt;code&gt;ListHostedZones&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stale TXT records&lt;/strong&gt;&lt;br&gt;
Sometimes old TXT entries block updates. Clean them in Route 53.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Annotations&lt;/strong&gt;&lt;br&gt;
ExternalDNS discovers hostnames in different ways:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;If you use a standard Kubernetes Ingress, the &lt;code&gt;spec.rules.host&lt;/code&gt; field is enough.&lt;/li&gt;
&lt;li&gt;If you expose a Service of type LoadBalancer (like Istio’s ingressgateway), add
 &lt;code&gt;external-dns.alpha.kubernetes.io/hostname&lt;/code&gt; with the hostnames.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ❌ Why I Didn’t Use AWS Load Balancer Controller
&lt;/h2&gt;

&lt;p&gt;Quick note: I skipped AWS Load Balancer Controller because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Istio already handled L7 routing&lt;/li&gt;
&lt;li&gt;We needed TCP/gRPC in addition to HTTP&lt;/li&gt;
&lt;li&gt;TLS was managed inside Istio&lt;/li&gt;
&lt;li&gt;One NLB was simpler and cheaper&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Final Thoughts
&lt;/h2&gt;

&lt;p&gt;ExternalDNS, cert-manager, and Istio work beautifully together — once you know the trick with annotations.&lt;/p&gt;

&lt;p&gt;Now I can add new subdomains like &lt;code&gt;api.yourdomain.com&lt;/code&gt; or &lt;code&gt;grafana.yourdomain.com&lt;/code&gt; without touching Route 53. ExternalDNS manages the records, cert-manager handles TLS, and Istio routes traffic where it belongs.&lt;/p&gt;

&lt;p&gt;Hopefully, this walkthrough saves you the debugging time I went through!&lt;/p&gt;




&lt;p&gt;💡 &lt;em&gt;Have you run into similar DNS headaches with Istio on EKS? Share your story — I’d love to compare notes.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.linkedin.com/in/niteshmore22/" rel="noopener noreferrer"&gt;📬 Connect with me on LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>sre</category>
      <category>dns</category>
      <category>istio</category>
    </item>
    <item>
      <title>🧠 Building Intelligent Kafka Health Probes in Go</title>
      <dc:creator>Nitesh More</dc:creator>
      <pubDate>Sat, 16 Aug 2025 05:21:07 +0000</pubDate>
      <link>https://forem.com/nitz22199/building-intelligent-kafka-health-probes-in-go-3dbb</link>
      <guid>https://forem.com/nitz22199/building-intelligent-kafka-health-probes-in-go-3dbb</guid>
      <description>&lt;p&gt;In production environments, health checks are your early warning system — but not all checks are created equal. While Kubernetes’ liveness and readiness probes can tell you if a service is &lt;em&gt;running&lt;/em&gt;, they can’t tell you if it's &lt;em&gt;working&lt;/em&gt;. We hit this problem head-on while building a Kafka-based CVE processing pipeline, and it led us to create &lt;strong&gt;intelligent probes&lt;/strong&gt; that know whether the consumer is truly healthy.&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%2Fw535nsegeb56qzxp11qf.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%2Fw535nsegeb56qzxp11qf.png" alt="Visual diagram" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🚨 The Problem with Basic Probes
&lt;/h2&gt;

&lt;p&gt;Our Kafka consumer processes CVE data, stores it in Postgres, and runs in Kubernetes. Initially, we used standard HTTP liveness/readiness endpoints that simply returned &lt;code&gt;200 OK&lt;/code&gt; if the process was up.&lt;/p&gt;

&lt;p&gt;But we started running into invisible failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The consumer would be &lt;strong&gt;running but stuck&lt;/strong&gt; due to a downstream DB issue.&lt;/li&gt;
&lt;li&gt;It would be &lt;strong&gt;assigned a partition&lt;/strong&gt; but not progressing.&lt;/li&gt;
&lt;li&gt;Or it would silently &lt;strong&gt;lag behind&lt;/strong&gt;, and no alerts were triggered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These kinds of failures wouldn’t be caught until days later, sometimes after critical delays in CVE ingestion.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧭 What We Needed
&lt;/h2&gt;

&lt;p&gt;We wanted probes that could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect if the consumer is &lt;strong&gt;stuck or not making progress&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Track &lt;strong&gt;offset movement&lt;/strong&gt; per partition&lt;/li&gt;
&lt;li&gt;Check if the &lt;strong&gt;Kafka topic and brokers&lt;/strong&gt; are reachable&lt;/li&gt;
&lt;li&gt;Verify &lt;strong&gt;Postgres availability&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Handle &lt;strong&gt;partition rebalances&lt;/strong&gt; without stale state&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 How We Solved It
&lt;/h2&gt;

&lt;p&gt;We used Go, the &lt;a href="https://github.com/Shopify/sarama" rel="noopener noreferrer"&gt;Sarama Kafka client&lt;/a&gt;, and some smart in-memory tracking. Here’s how it works:&lt;/p&gt;

&lt;h3&gt;
  
  
  🧮 1. Offset Tracking
&lt;/h3&gt;

&lt;p&gt;We used &lt;code&gt;sync.Map&lt;/code&gt; to store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;offsetMap&lt;/code&gt;: the most recent offset we’ve seen per partition&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lastCommittedOffsets&lt;/code&gt;: used to detect if the consumer has stopped progressing
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;offsetMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔍 2. Intelligent Liveness Check
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;/liveness&lt;/code&gt; endpoint does more than return &lt;code&gt;200 OK&lt;/code&gt;. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connects to Kafka&lt;/li&gt;
&lt;li&gt;Fetches the latest offset for each partition&lt;/li&gt;
&lt;li&gt;Compares it with our last seen offset&lt;/li&gt;
&lt;li&gt;Checks if there’s no new data OR if the offset hasn’t changed over time (indicating a stuck consumer)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;currentOffset&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;committedOffset&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;currentOffset&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;committedOffset&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// no new messages to process&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lastCommitted&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;committedOffset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// stuck — offset hasn't advanced&lt;/span&gt;
    &lt;span class="n"&gt;unhealthy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  📦 3. Readiness Check
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;/readiness&lt;/code&gt; probe ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At least one Kafka broker is reachable&lt;/li&gt;
&lt;li&gt;The Kafka topic exists&lt;/li&gt;
&lt;li&gt;Postgres is reachable using &lt;code&gt;.PingContext()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only if &lt;em&gt;all&lt;/em&gt; of these are true does the service report itself as “ready.”&lt;/p&gt;




&lt;h3&gt;
  
  
  🔁 4. Handling Rebalances
&lt;/h3&gt;

&lt;p&gt;During rebalancing, partitions are reassigned, and we clean up the stale state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;offsetMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;claim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Partition&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;lastCommittedOffsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;claim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Partition&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents invalid health status when the partition is no longer assigned to the consumer.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Why This is "Intelligent"
&lt;/h2&gt;

&lt;p&gt;Unlike typical health checks, our probes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track &lt;strong&gt;progress&lt;/strong&gt;, not just availability&lt;/li&gt;
&lt;li&gt;Are &lt;strong&gt;partition-aware&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Can detect &lt;strong&gt;silent failures&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Check both &lt;strong&gt;Kafka&lt;/strong&gt; and &lt;strong&gt;DB dependencies&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;React to &lt;strong&gt;consumer rebalances&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allowed us to catch real issues — like stuck consumers or dead DB connections — &lt;em&gt;before&lt;/em&gt; they caused data loss or delays.&lt;/p&gt;




&lt;h2&gt;
  
  
  📈 Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Don’t rely on basic probes for stateful services like Kafka consumers&lt;/li&gt;
&lt;li&gt;Offset movement is a powerful signal for consumer health&lt;/li&gt;
&lt;li&gt;Observability is about understanding &lt;strong&gt;behavior&lt;/strong&gt;, not just uptime&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Conclusion
&lt;/h2&gt;

&lt;p&gt;This approach has saved us from multiple production incidents by proactively identifying when the consumer isn’t doing useful work. We now treat our consumers like &lt;strong&gt;stateful workers&lt;/strong&gt; — with health checks that are aware of &lt;strong&gt;what they’re supposed to be doing&lt;/strong&gt;, not just whether they’re online.&lt;/p&gt;




&lt;p&gt;🙌 Let’s Connect&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you enjoyed this post or have thoughts to share, feel free to reach out — I’d love to chat about Kafka, distributed systems, or anything DevOps.&lt;/p&gt;

&lt;p&gt;📬 &lt;a href="https://www.linkedin.com/in/niteshmore22/" rel="noopener noreferrer"&gt;Connect with me on LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>kafka</category>
      <category>devops</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How I Built Budget Brain🧠💰 in 12 Hours with Kiro as My AI Project Manager</title>
      <dc:creator>Nitesh More</dc:creator>
      <pubDate>Sat, 16 Aug 2025 01:41:02 +0000</pubDate>
      <link>https://forem.com/nitz22199/how-i-built-budget-brain-in-12-hours-with-kiro-as-my-ai-project-manager-1nl0</link>
      <guid>https://forem.com/nitz22199/how-i-built-budget-brain-in-12-hours-with-kiro-as-my-ai-project-manager-1nl0</guid>
      <description>&lt;h2&gt;
  
  
  🚀 The Challenge
&lt;/h2&gt;

&lt;p&gt;Hackathons are always a race against the clock. This time, I set out to build &lt;strong&gt;Budget Brain&lt;/strong&gt;: an AI-powered advertising budget optimizer that uses Monte Carlo simulation and multi-algorithm validation to help businesses allocate ad spend smarter.&lt;/p&gt;

&lt;p&gt;The goal?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time pipeline visualization&lt;/li&gt;
&lt;li&gt;Multi-algorithm optimization (Monte Carlo + Gradient + Bayesian)&lt;/li&gt;
&lt;li&gt;Confidence scoring and validation&lt;/li&gt;
&lt;li&gt;Accessibility-first UI&lt;/li&gt;
&lt;li&gt;Production quality in &lt;strong&gt;just 12 hours&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds impossible, right?&lt;/p&gt;

&lt;p&gt;It would have been — without &lt;strong&gt;Kiro&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤝 Enter Kiro: My AI Technical Project Manager
&lt;/h2&gt;

&lt;p&gt;Kiro became the &lt;strong&gt;organizing brain&lt;/strong&gt; behind Budget Brain. Instead of drowning in feature creep, last-minute architecture decisions, or messy code, Kiro kept me laser-focused with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📋 &lt;strong&gt;Specs &amp;amp; Planning&lt;/strong&gt;: Clear requirements, user stories, and acceptance criteria&lt;/li&gt;
&lt;li&gt;🏗️ &lt;strong&gt;Architecture Blueprints&lt;/strong&gt;: Interfaces, component structures, and pipeline layouts&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Task Tracking&lt;/strong&gt;: 24 implementation tasks with checkboxes (all completed!)&lt;/li&gt;
&lt;li&gt;🪝 &lt;strong&gt;Code Quality Hooks&lt;/strong&gt;: Automated reviews for performance, accessibility, and maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words: I was coding at hackathon speed, but with enterprise-level discipline.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 How I Structured Conversations with Kiro
&lt;/h2&gt;

&lt;p&gt;I started with &lt;strong&gt;simple prompts&lt;/strong&gt;, and Kiro turned them into &lt;strong&gt;complete systems&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; &lt;em&gt;“I want to create a decision pipeline to enhance system accuracy.”&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Kiro:&lt;/strong&gt; Broke this into &lt;strong&gt;multi-algorithm validation, ensemble methods, and confidence scoring&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; &lt;em&gt;“How do I combine multiple optimization algorithms reliably?”&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Kiro:&lt;/strong&gt; Generated the &lt;code&gt;AccuracyEnhancementService&lt;/code&gt; architecture with parallel algorithm execution and result combination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; &lt;em&gt;“What’s the best way to validate optimization results?”&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;Kiro:&lt;/strong&gt; Produced a &lt;strong&gt;12-task plan&lt;/strong&gt; covering gradient optimization, Bayesian modeling, LLM validation, and benchmark comparison.&lt;/p&gt;

&lt;p&gt;👉 What began as vague ideas became &lt;strong&gt;concrete TypeScript interfaces, workflows, and production code.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🪝 Kiro Hooks: Automated Code Review Under Pressure
&lt;/h2&gt;

&lt;p&gt;Even while sprinting, Kiro kept quality high with &lt;strong&gt;automated hooks&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Code Review&lt;/strong&gt;: Flagged long functions, duplicate logic, and type safety issues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Budget Brain–Specific Checks&lt;/strong&gt;: Verified pipeline stage error handling, algorithm efficiency, and accessibility compliance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Optimization&lt;/strong&gt;: Detected unnecessary React re-renders, suggested caching in Monte Carlo + AccuracyEnhancementService&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality Gates&lt;/strong&gt;: Pre-commit scoring, test coverage checks, maintainability reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 The result: No technical debt — even in a hackathon sprint.&lt;/p&gt;




&lt;h2&gt;
  
  
  📑 Spec-to-Code: The Secret Weapon
&lt;/h2&gt;

&lt;p&gt;I paired Kiro with a &lt;strong&gt;spec-to-code workflow&lt;/strong&gt; that looked like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Requirements.md&lt;/strong&gt; → User stories + acceptance criteria&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design.md&lt;/strong&gt; → Technical architecture + TypeScript interfaces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tasks.md&lt;/strong&gt; → 12 concrete implementation tasks with checkboxes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Flow:&lt;/strong&gt;&lt;br&gt;
👉 User Story → Technical Design → Implementation Tasks → Production Code&lt;/p&gt;

&lt;p&gt;This meant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero architecture decisions during coding&lt;/li&gt;
&lt;li&gt;Parallel dev (frontend + backend in sync)&lt;/li&gt;
&lt;li&gt;Tests and accessibility baked in&lt;/li&gt;
&lt;li&gt;No scope creep (24 tasks, nothing more)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🏆 The Outcome
&lt;/h2&gt;

&lt;p&gt;With Kiro’s help, I shipped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time pipeline visualization with animated stages&lt;/li&gt;
&lt;li&gt;Multi-algorithm ensemble (Monte Carlo, Gradient, Bayesian)&lt;/li&gt;
&lt;li&gt;Confidence scoring + AI validation&lt;/li&gt;
&lt;li&gt;600+ automated tests&lt;/li&gt;
&lt;li&gt;Accessible, mobile-optimized UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in &lt;strong&gt;12 hours&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Kiro wasn’t just an assistant. It was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;planner&lt;/strong&gt; (clear roadmap, specs, and tasks)&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;architect&lt;/strong&gt; (interfaces, algorithms, data models)&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;code reviewer&lt;/strong&gt; (hooks, checks, and optimizations)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Takeaway
&lt;/h2&gt;

&lt;p&gt;Hackathons usually trade speed for quality. With Kiro, I had both.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I moved fast — but with a plan.&lt;/li&gt;
&lt;li&gt;I built complex systems — without messy shortcuts.&lt;/li&gt;
&lt;li&gt;I delivered production-quality features — under hackathon pressure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;Bottom line:&lt;/strong&gt; Kiro acted as my AI project manager, architect, and reviewer all in one. Budget Brain wouldn’t have been possible without it.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔮 Looking Ahead
&lt;/h2&gt;

&lt;p&gt;Budget Brain is just the start. The spec-to-code structure and Kiro-powered workflow could be applied to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SaaS MVPs&lt;/li&gt;
&lt;li&gt;Enterprise-grade feature sprints&lt;/li&gt;
&lt;li&gt;Team collaboration with automated quality gates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hackathons taught me that &lt;strong&gt;AI-assisted engineering discipline is the new superpower.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;✍️ &lt;em&gt;Built with ❤️ during [Code with Kiro Hackathon] 2025.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://cute-meerkat-39f1f9.netlify.app/" rel="noopener noreferrer"&gt;Click here to try&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/niteshmore22/" rel="noopener noreferrer"&gt;Connect with me&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kiro</category>
    </item>
  </channel>
</rss>
