<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Furkan Köykıran</title>
    <description>The latest articles on DEV Community by Furkan Köykıran (@furkankoykiran).</description>
    <link>https://dev.to/furkankoykiran</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%2F3757458%2F729acfee-83c6-4805-971d-c7d9090d2bed.jpg</url>
      <title>DEV Community: Furkan Köykıran</title>
      <link>https://dev.to/furkankoykiran</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/furkankoykiran"/>
    <language>en</language>
    <item>
      <title>freqtrade-mcp: Bota Claude Üzerinden Sor</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Sat, 04 Apr 2026 14:14:52 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/freqtrade-mcp-bota-claude-uzerinden-sor-2me8</link>
      <guid>https://dev.to/furkankoykiran/freqtrade-mcp-bota-claude-uzerinden-sor-2me8</guid>
      <description>&lt;p&gt;Freqtrade botu çalıştırıyorum. Stratejim var, bot işini yapıyor, benim müdahaleye gerek yok. Teorikte.&lt;/p&gt;

&lt;p&gt;Pratikte gece 23'te ekrana bakıyorum.&lt;/p&gt;

&lt;p&gt;Bir şey kaybetmiş miyim? Yoksa bir fırsat mı kaçtı? Bot kapanmış mıdır? Aynı bakiyeyi görüyorum ama "acaba" duygusu geçmiyor. FreqUI'yı açıyorum, sekmelere tıklıyorum, rakamları görüyorum, kapatıyorum. On beş dakika sonra tekrar açıyorum.&lt;/p&gt;

&lt;p&gt;Bu süreci kısaltmak için &lt;a href="https://github.com/furkankoykiran/freqtrade-mcp" rel="noopener noreferrer"&gt;@furkankoykiran/freqtrade-mcp&lt;/a&gt;'yi yazdım — Freqtrade'in REST API'sini Claude'a açan, 15 araçlık bir TypeScript MCP sunucusu. Claude Desktop, Cursor, Cline, &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; konuşan her şeyle çalışıyor.&lt;/p&gt;

&lt;p&gt;Artık FreqUI açmak yerine Claude'a soruyorum. Cevap geliyor. Geçiyorum.&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%2F905iktsn1ygt46nc3a16.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%2F905iktsn1ygt46nc3a16.png" alt="Freqtrade FreqUI" width="800" height="403"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Freqtrade — artık açmak zorunda kalmadan da bilgi alabilirsin.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Neye Yarıyor
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Portföy Durumu
&lt;/h3&gt;

&lt;p&gt;Gece 23'teki sorular genellikle bunlar:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Bu ay net pozitif miyim, yoksa bakmamak mı lazım?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Şu an ne kadar USDT açık pozisyonda, ne kadarı boşta bekliyor?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Hangi çiftler iyi gidiyor?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;get_profit_stats&lt;/code&gt;, &lt;code&gt;get_balance&lt;/code&gt;, &lt;code&gt;get_performance&lt;/code&gt; bunları karşılıyor. Claude ham JSON'ı okunaklı hale getiriyor. Sayıları kendin çözmeye çalışmak zorunda kalmıyorsun.&lt;/p&gt;


&lt;h3&gt;
  
  
  Pozisyonlar
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Açık işlemler ne durumda, zararda olan var mı?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"42 numaralı işlem — açılış tarihi ne, şu anki K/Z ne?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Son 10 kapanan işlemi göster."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bot aynı anda onlarca pozisyon taşıyabiliyor. Her satırı kendin okumak yerine Claude'a sormak çok daha hızlı. Sonuç doğrudan geliyor.&lt;/p&gt;


&lt;h3&gt;
  
  
  Piyasa Verisi
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"BTC/USDT 4 saatlik, son 50 mum."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"ETH/USDT şu an 1 saatlikte nasıl görünüyor?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;get_market_data&lt;/code&gt; canlı OHLCV verisini doğrudan borsadan çekiyor. Claude grafiğe bakıp bir yorum yapabilir. Ne yapacağın sana kalmış.&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%2Fyk5vsvtmmpk6x6473fye.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%2Fyk5vsvtmmpk6x6473fye.png" alt="Freqtrade Backtesting" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Freqtrade'in analiz ekranı — MCP sunucusu da aynı veriyi anlık çekiyor.&lt;/em&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  Liste Yönetimi
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"LUNA/USDT'yi kara listeye ekle."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Beyaz listede ne var? BNB/BTC'yi kara listeden çıkar."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Normalde ya config dosyasını editliyorsun ya da FreqUI'da menüler arasında geziniyorsun. Şimdi tek cümle.&lt;/p&gt;


&lt;h3&gt;
  
  
  Manuel İşlem
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Şu an 100 USDT ETH al."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"BTC/USDT'de 50 USDT ile short aç."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"7 numaralı işlemi kapat."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;execute_trade&lt;/code&gt; ve &lt;code&gt;force_exit_trade&lt;/code&gt; strateji beklemeden anında çalışıyor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Önemli:&lt;/strong&gt; Gerçek borsa, gerçek para, geri alınmıyor. "Dikkatli ol" burada gerçekten önemli. Onay ekranı yok, borsa "test ediyordum" demeyi tanımıyor.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  Bot Yönetimi
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Botu durdur, config değiştirecektim."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Yeniden başlatmadan config'i yenile."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Bot son ne zaman çalıştı, hâlâ ayakta mı?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;get_bot_info&lt;/code&gt; sürüm ve sağlık verisini bir arada veriyor. Botun gerçekten çalışıp çalışmadığını öğrenmek için FreqUI açmana gerek kalmıyor.&lt;/p&gt;


&lt;h2&gt;
  
  
  Kurulum
&lt;/h2&gt;

&lt;p&gt;Freqtrade &lt;code&gt;config.json&lt;/code&gt; içinde REST API'yi etkinleştir (varsayılan olarak kapalı gelir), ardından Claude Desktop config'ine ekle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"freqtrade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@furkankoykiran/freqtrade-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"FREQTRADE_API_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"FREQTRADE_USERNAME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Freqtrader"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"FREQTRADE_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YourPassword"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Desktop'ı yeniden başlat. 15 araç hazır, build adımı yok.&lt;/p&gt;




&lt;h2&gt;
  
  
  Araçlar
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Kategori&lt;/th&gt;
&lt;th&gt;Araçlar&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hesap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;get_profit_stats&lt;/code&gt;, &lt;code&gt;get_balance&lt;/code&gt;, &lt;code&gt;get_performance&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;İşlemler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;get_open_trades&lt;/code&gt;, &lt;code&gt;get_trade&lt;/code&gt;, &lt;code&gt;get_trade_history&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Piyasa Verisi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;get_market_data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Çift Listeleri&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;get_whitelist&lt;/code&gt;, &lt;code&gt;get_blacklist&lt;/code&gt;, &lt;code&gt;add_to_blacklist&lt;/code&gt;, &lt;code&gt;remove_from_blacklist&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;İşlem Açma&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;execute_trade&lt;/code&gt;, &lt;code&gt;force_exit_trade&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bot Yönetimi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;start_bot&lt;/code&gt;, &lt;code&gt;stop_bot&lt;/code&gt;, &lt;code&gt;reload_config&lt;/code&gt;, &lt;code&gt;get_bot_info&lt;/code&gt;, &lt;code&gt;get_locks&lt;/code&gt;, &lt;code&gt;delete_lock&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Sonuç
&lt;/h2&gt;

&lt;p&gt;Temelde şunu çözmek istedim: FreqUI'yı açmadan bota bakabileyim. REST API zaten oradaydı, sadece arayüzün arkasına gömülüydü.&lt;/p&gt;

&lt;p&gt;Artık Claude'a soruyorum. O söylüyor. Geçiyorum.&lt;/p&gt;

&lt;p&gt;Pek tabii "acaba değişmiş mi" duygusu hâlâ geçmiyor, ama en azından sormak kolaylaştı.&lt;/p&gt;

&lt;p&gt;Proje açık kaynak ve MIT lisanslı. Freqtrade REST API kurulumu dahil tam kılavuz README'de.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/furkankoykiran/freqtrade-mcp" rel="noopener noreferrer"&gt;github.com/furkankoykiran/freqtrade-mcp&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu yazı &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt; aracılığıyla DEV.to'ya gönderilmiştir.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>freqtrade</category>
      <category>typescript</category>
      <category>claude</category>
    </item>
    <item>
      <title>freqtrade-mcp: Ask Claude to Check Your Trades</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Sat, 04 Apr 2026 14:14:38 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/freqtrade-mcp-ask-claude-to-check-your-trades-44hj</link>
      <guid>https://dev.to/furkankoykiran/freqtrade-mcp-ask-claude-to-check-your-trades-44hj</guid>
      <description>&lt;p&gt;I run a Freqtrade bot. Like most people who run trading bots, I tell myself I'm "not constantly checking it" — and then check it constantly.&lt;/p&gt;

&lt;p&gt;The ritual: open browser, log into FreqUI, click through tabs, squint at numbers, close browser, reopen browser 10 minutes later. It adds up.&lt;/p&gt;

&lt;p&gt;At some point I thought: I already have Claude open. Why am I switching contexts to a UI when the bot has a perfectly good REST API?&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/furkankoykiran/freqtrade-mcp" rel="noopener noreferrer"&gt;@furkankoykiran/freqtrade-mcp&lt;/a&gt; — a TypeScript MCP server with 15 tools that lets you ask Claude what your bot is doing. Works with Claude Desktop, Cursor, Cline, anything that speaks &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt;. You ask in plain English. The bot answers.&lt;/p&gt;

&lt;p&gt;Yes, I built an AI wrapper around my trading bot so I can talk to it through a different AI. I'm at peace with this.&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%2F905iktsn1ygt46nc3a16.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%2F905iktsn1ygt46nc3a16.png" alt="Freqtrade FreqUI" width="800" height="403"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Freqtrade trading interface — now accessible via natural language through Claude.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What You Can Do
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Portfolio &amp;amp; Performance
&lt;/h3&gt;

&lt;p&gt;The questions I actually ask my bot, at various hours of the day:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"How much profit have I made total? Please be honest."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"What's my current balance — how much is deployed vs sitting in USDT doing nothing?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Which pairs are performing well? Show me the top 5 so I can feel better about my decisions."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Am I net positive this month or should I not look?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;get_profit_stats&lt;/code&gt;, &lt;code&gt;get_balance&lt;/code&gt;, and &lt;code&gt;get_performance&lt;/code&gt; handle all of these. Claude gets back structured JSON from the Freqtrade API and gives you a readable summary instead of making you parse numbers yourself at 11pm.&lt;/p&gt;


&lt;h3&gt;
  
  
  Open Trades &amp;amp; History
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"What trades are open right now? Any in the red that I should know about?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Show me trade #42 — when did it open, what's the P/L, and should I be worried?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Give me the last 10 closed trades."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The bot can have dozens of open positions at once. Scanning a raw JSON blob yourself at midnight is not the move. Claude summarizes it. You move on.&lt;/p&gt;


&lt;h3&gt;
  
  
  Market Data on Demand
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Fetch the last 50 BTC/USDT candles on the 4h timeframe."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"What does the ETH/USDT 1h chart look like right now?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;get_market_data&lt;/code&gt; tool pulls live OHLCV data directly from the exchange through Freqtrade. Ask Claude what the 4h chart looks like right now. It'll tell you something. Whether you should act on it is your problem.&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%2Fyk5vsvtmmpk6x6473fye.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%2Fyk5vsvtmmpk6x6473fye.png" alt="Freqtrade Backtesting" width="800" height="459"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Freqtrade's strategy analysis interface — the same data the MCP server can fetch on demand.&lt;/em&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  Pair List Management
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Add LUNA/USDT to the blacklist."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"What's currently on my whitelist? Remove BNB/BTC from the blacklist."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Normally this means editing a JSON config file, reloading, and hoping you didn't break anything. Or navigating FreqUI through three menu levels to find the right panel. With the MCP server it's a sentence. Done.&lt;/p&gt;


&lt;h3&gt;
  
  
  Manual Trade Execution
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Buy 100 USDT of ETH right now."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Open a short on BTC/USDT with a 50 USDT stake."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Exit trade #7 at market price."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;execute_trade&lt;/code&gt; and &lt;code&gt;force_exit_trade&lt;/code&gt; bypass strategy signals entirely — useful when you want to act on something the bot wouldn't otherwise touch.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This executes immediately against the live exchange. "Use with intention" is doing a lot of heavy lifting in that sentence. No confirmation dialog. No undo. The exchange doesn't care that you were just testing the API.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  Bot Lifecycle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Stop the bot — I need to edit the config before it does something."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Reload the config without restarting, the bot is mid-cycle."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"What version is the bot on? Did it run recently or has it been sitting there silently failing?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stopping a live trading bot always feels slightly dramatic. One call handles it. &lt;code&gt;get_bot_info&lt;/code&gt; combines version and health data so you know whether the bot is actually running or just pretending to be.&lt;/p&gt;


&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Enable the REST API in your Freqtrade &lt;code&gt;config.json&lt;/code&gt; (it's off by default, for good reason), then add the server to your Claude Desktop config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"freqtrade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@furkankoykiran/freqtrade-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"FREQTRADE_API_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"FREQTRADE_USERNAME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Freqtrader"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"FREQTRADE_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YourPassword"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Claude Desktop. All 15 tools show up immediately, no build step required.&lt;/p&gt;




&lt;h2&gt;
  
  
  Available Tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Account&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;get_profit_stats&lt;/code&gt;, &lt;code&gt;get_balance&lt;/code&gt;, &lt;code&gt;get_performance&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Trades&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;get_open_trades&lt;/code&gt;, &lt;code&gt;get_trade&lt;/code&gt;, &lt;code&gt;get_trade_history&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Market Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;get_market_data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pair Lists&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;get_whitelist&lt;/code&gt;, &lt;code&gt;get_blacklist&lt;/code&gt;, &lt;code&gt;add_to_blacklist&lt;/code&gt;, &lt;code&gt;remove_from_blacklist&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;execute_trade&lt;/code&gt;, &lt;code&gt;force_exit_trade&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lifecycle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;start_bot&lt;/code&gt;, &lt;code&gt;stop_bot&lt;/code&gt;, &lt;code&gt;reload_config&lt;/code&gt;, &lt;code&gt;get_bot_info&lt;/code&gt;, &lt;code&gt;get_locks&lt;/code&gt;, &lt;code&gt;delete_lock&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;The honest version: I was tired of opening FreqUI to check one number. The REST API was already there, just buried behind a browser tab I had to switch to.&lt;/p&gt;

&lt;p&gt;Now I ask Claude. It tells me. I close the laptop slightly less anxious than before.&lt;/p&gt;

&lt;p&gt;The project is open source and MIT licensed. The README has the full setup guide, including how to configure the Freqtrade REST API if you haven't done that yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/furkankoykiran/freqtrade-mcp" rel="noopener noreferrer"&gt;github.com/furkankoykiran/freqtrade-mcp&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was published to DEV.to via &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>freqtrade</category>
      <category>typescript</category>
      <category>claude</category>
    </item>
    <item>
      <title>awesome-trending-repos: Modern Web Interface for GitHub Trending</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Fri, 27 Mar 2026 20:12:20 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/awesome-trending-repos-modern-web-interface-for-github-trending-26b5</link>
      <guid>https://dev.to/furkankoykiran/awesome-trending-repos-modern-web-interface-for-github-trending-26b5</guid>
      <description>&lt;p&gt;In my previous blog post, I introduced the &lt;a href="https://github.com/furkankoykiran/awesome-trending-repos" rel="noopener noreferrer"&gt;awesome-trending-repos&lt;/a&gt; project. Back then, the project only wrote data to a README.md file. Things have changed. The project is now a fully functional modern web application.&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%2Fr8h4rlndbfpf10x48g0y.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%2Fr8h4rlndbfpf10x48g0y.png" alt="CI/CD Pipeline"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Automated build and deployment process with GitHub Actions&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Why a Web Interface?
&lt;/h2&gt;

&lt;p&gt;A README.md file works, but it's static. To track trending projects effectively, I wanted a more interactive experience. Users needed to be able to filter by programming language, search repositories, and see data visualized with charts.&lt;/p&gt;

&lt;p&gt;So I built a modern single-page application (SPA) with React + Vite.&lt;/p&gt;


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

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

&lt;ul&gt;
&lt;li&gt;React 19 - Latest version&lt;/li&gt;
&lt;li&gt;Vite - Fast dev server and build tool&lt;/li&gt;
&lt;li&gt;Tailwind CSS v4 - Utility-first styling&lt;/li&gt;
&lt;li&gt;Framer Motion - Animations&lt;/li&gt;
&lt;li&gt;Recharts - Data visualization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Backend/Infrastructure:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions - Automation&lt;/li&gt;
&lt;li&gt;GitHub Pages - Hosting&lt;/li&gt;
&lt;li&gt;Custom Domain - furkankoykiran.com.tr&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;The core project structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awesome-trending-repos/
├── src/
│   ├── App.jsx          # Main React component
│   ├── main.jsx         # Entry point
│   └── index.css        # Tailwind + custom styles
├── scripts/
│   └── update.js        # Trending data scrape script
├── public/
│   ├── data/
│   │   └── trending.json # Frontend data source
│   └── logo.png
├── .github/workflows/
│   └── update-trends.yml # CI/CD pipeline
└── vite.config.js       # GitHub Pages config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  GitHub Pages Integration
&lt;/h2&gt;

&lt;p&gt;When using Vite with GitHub Pages, the most important configuration is the &lt;code&gt;base&lt;/code&gt; path. If your project runs in a subdirectory (e.g., &lt;code&gt;github.io/repo-name&lt;/code&gt;), you must specify this in &lt;code&gt;vite.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tailwindcss&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tailwindcss/vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;tailwindcss&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/awesome-trending-repos/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// GitHub Pages subdirectory&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this setting, asset paths will break in production and you'll get 404 errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  GitHub Actions Workflow
&lt;/h2&gt;

&lt;p&gt;The workflow runs every day at midnight UTC:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fetch trending data&lt;/strong&gt; - Scrape GitHub Trending page&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build frontend&lt;/strong&gt; - Create dist/ folder with &lt;code&gt;npm run build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commit data&lt;/strong&gt; - Commit README and data files if changed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt; - Distribute to GitHub Pages
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/update-trends.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update and Deploy Trends&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;  &lt;span class="c1"&gt;# Daily at midnight&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;update-and-build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&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;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&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;Run update script&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run update&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&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;Build frontend&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload artifact&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-pages-artifact@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./dist'&lt;/span&gt;

  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;environment&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;github-pages&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.deployment.outputs.page_url }}&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;update-and-build&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to GitHub Pages&lt;/span&gt;
        &lt;span class="na"&gt;id&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;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/deploy-pages@v4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fuc8fujztlcirz2c5i2u5.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%2Fuc8fujztlcirz2c5i2u5.png" alt="Deployment Flow"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Automated deployment flow&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Frontend Features
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Language Filtering
&lt;/h3&gt;

&lt;p&gt;Users can filter by programming language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;languages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;))];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredRepos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matchesLang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matchesSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;matchesLang&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;matchesSearch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Search Function
&lt;/h3&gt;

&lt;p&gt;Real-time search across repo name, owner, and description.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Visual Statistics
&lt;/h3&gt;

&lt;p&gt;Recharts library for language distribution bar chart and growth leaders list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponsiveContainer&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BarChart&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;insights&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;topLanguages&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CartesianGrid&lt;/span&gt; &lt;span class="nx"&gt;strokeDasharray&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8 8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ffffff03&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;XAxis&lt;/span&gt; &lt;span class="nx"&gt;dataKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#475569&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;YAxis&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#475569&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Tooltip&lt;/span&gt; &lt;span class="nx"&gt;contentStyle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rgba(15, 23, 42, 0.9)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Bar&lt;/span&gt; &lt;span class="nx"&gt;dataKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;insights&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;topLanguages&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cell&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;getLangColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Bar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BarChart&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ResponsiveContainer&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Deployment Feed
&lt;/h3&gt;

&lt;p&gt;A feed entry is created for each update. Users can see the deployment history.&lt;/p&gt;




&lt;h2&gt;
  
  
  Custom Domain Setup
&lt;/h2&gt;

&lt;p&gt;To use a custom domain with GitHub Pages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create CNAME file&lt;/strong&gt; - Add your domain to &lt;code&gt;public/CNAME&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   furkankoykiran.com.tr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;DNS setting&lt;/strong&gt; - At your domain provider:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;   &lt;span class="n"&gt;CNAME&lt;/span&gt; &lt;span class="n"&gt;furkankoykiran&lt;/span&gt;.&lt;span class="n"&gt;github&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS&lt;/strong&gt; - GitHub Pages automatically provides SSL with Let's Encrypt.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Performance Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Asset Optimization
&lt;/h3&gt;

&lt;p&gt;Vite production build automatically does minification and tree-shaking. For large images, consider using optimized images instead of putting everything in &lt;code&gt;public/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Lazy Loading
&lt;/h3&gt;

&lt;p&gt;For large lists, consider virtual scrolling. Not needed for this project with 25 repos, but good to know if you scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Caching
&lt;/h3&gt;

&lt;p&gt;GitHub Pages automatically adds cache headers. For &lt;code&gt;index.html&lt;/code&gt;, use cache-busting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rollupOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;entryFileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`assets/[name].[hash].js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;chunkFileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`assets/[name].[hash].js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;assetFileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`assets/[name].[hash].[ext]`&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Live Demo
&lt;/h2&gt;

&lt;p&gt;The project is currently live at &lt;a href="https://furkankoykiran.com.tr/awesome-trending-repos/" rel="noopener noreferrer"&gt;furkankoykiran.com.tr/awesome-trending-repos&lt;/a&gt;. It updates automatically every day.&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%2Fzywpheil54s5wiyo2zt6.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%2Fzywpheil54s5wiyo2zt6.png" alt="Project Logo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Project logo&lt;/em&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%2Fdw2qfuyhzi0xscpwksx9.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%2Fdw2qfuyhzi0xscpwksx9.png" alt="OG Image"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Open Graph preview image&lt;/em&gt;&lt;/p&gt;




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

&lt;p&gt;Moving from a README.md to a modern web application significantly improved the project's usability. Users now have an interactive experience instead of just a static list.&lt;/p&gt;

&lt;p&gt;The GitHub Pages + Vite combination is an excellent solution for static sites. Free, fast, and fully automated with CI/CD.&lt;/p&gt;

&lt;p&gt;The project is fully open source. If you want to contribute, send a pull request to the &lt;a href="https://github.com/furkankoykiran/awesome-trending-repos" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://blog.furkankoykiran.com.tr" rel="noopener noreferrer"&gt;blog.furkankoykiran.com.tr&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>vite</category>
      <category>github</category>
      <category>webdev</category>
    </item>
    <item>
      <title>awesome-trending-repos: GitHub Trending için Modern Web Arayüzü</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Fri, 27 Mar 2026 20:12:18 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/awesome-trending-repos-github-trending-icin-modern-web-arayuzu-m7n</link>
      <guid>https://dev.to/furkankoykiran/awesome-trending-repos-github-trending-icin-modern-web-arayuzu-m7n</guid>
      <description>&lt;p&gt;Önceki blog yazımda &lt;a href="https://github.com/furkankoykiran/awesome-trending-repos" rel="noopener noreferrer"&gt;awesome-trending-repos&lt;/a&gt; projesinden bahsetmiştim. O zamanlar proje sadece README.md dosyasına veri yazıyordu. Artık things changed. Proje artık tam fonksiyonlu bir modern web uygulaması.&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%2Fr8h4rlndbfpf10x48g0y.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%2Fr8h4rlndbfpf10x48g0y.png" alt="CI/CD Pipeline" width="800" height="354"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;GitHub Actions ile otomatik build ve deploy süreci&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Neden Web Arayüzü?
&lt;/h2&gt;

&lt;p&gt;README.md dosyası işe yarar ama statiktir. Trending projeleri takip etmek için daha interaktif bir deneyim istedim. Kullanıcıların dil bazlı filtreleme yapabilmesi, arama yapabilmesi ve grafiklerle verileri görebilmesi gerekliydi.&lt;/p&gt;

&lt;p&gt;Bu yüzden React + Vite ile modern bir single-page application (SPA) geliştirdim.&lt;/p&gt;


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

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

&lt;ul&gt;
&lt;li&gt;React 19 - Son sürüm&lt;/li&gt;
&lt;li&gt;Vite - Hızlı dev server ve build&lt;/li&gt;
&lt;li&gt;Tailwind CSS v4 - Utility-first styling&lt;/li&gt;
&lt;li&gt;Framer Motion - Animasyonlar&lt;/li&gt;
&lt;li&gt;Recharts - Veri görselleştirme&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Backend/Infrastructure:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions - Otomasyon&lt;/li&gt;
&lt;li&gt;GitHub Pages - Hosting&lt;/li&gt;
&lt;li&gt;Custom Domain - furkankoykiran.com.tr&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Proje Yapısı
&lt;/h2&gt;

&lt;p&gt;Projenin temel dizini şöyle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awesome-trending-repos/
├── src/
│   ├── App.jsx          # Ana React bileşeni
│   ├── main.jsx         # Entry point
│   └── index.css        # Tailwind + custom styles
├── scripts/
│   └── update.js        # Trending veri scrape script
├── public/
│   ├── data/
│   │   └── trending.json # Frontend veri kaynağı
│   └── logo.png
├── .github/workflows/
│   └── update-trends.yml # CI/CD pipeline
└── vite.config.js       # GitHub Pages config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  GitHub Pages Entegrasyonu
&lt;/h2&gt;

&lt;p&gt;Vite ile GitHub Pages kullanırken en önemli nokta &lt;code&gt;base&lt;/code&gt; path konfigürasyonudur. Projeniz bir subdirectory'de çalışacaksa (örn: &lt;code&gt;github.io/repo-name&lt;/code&gt;), &lt;code&gt;vite.config.js&lt;/code&gt; dosyasında bunu belirtmelisiniz:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tailwindcss&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tailwindcss/vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;tailwindcss&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/awesome-trending-repos/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// GitHub Pages subdirectory&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu ayar olmadan, production'da asset path'leri bozulur ve 404 hatası alırsınız.&lt;/p&gt;




&lt;h2&gt;
  
  
  GitHub Actions Workflow
&lt;/h2&gt;

&lt;p&gt;Her gün gece yarısı UTC'de çalışan workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Trending verisi çek&lt;/strong&gt; - GitHub Trending sayfasını scrape et&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend build&lt;/strong&gt; - &lt;code&gt;npm run build&lt;/code&gt; ile dist/ klasörünü oluştur&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data commit&lt;/strong&gt; - Değişiklik varsa README ve data dosyalarını commit et&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy&lt;/strong&gt; - GitHub Pages'e dağıt
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/update-trends.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update and Deploy Trends&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;  &lt;span class="c1"&gt;# Her gün gece yarısı&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;update-and-build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&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;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&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;Run update script&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run update&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&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;Build frontend&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload artifact&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-pages-artifact@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./dist'&lt;/span&gt;

  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;environment&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;github-pages&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.deployment.outputs.page_url }}&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;update-and-build&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to GitHub Pages&lt;/span&gt;
        &lt;span class="na"&gt;id&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;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/deploy-pages@v4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fuc8fujztlcirz2c5i2u5.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%2Fuc8fujztlcirz2c5i2u5.png" alt="Deployment Flow" width="800" height="605"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Otomatik deployment akışı&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Frontend Özellikleri
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Dil Filtreleme
&lt;/h3&gt;

&lt;p&gt;Kullanıcılar programlama diline göre filtreleme yapabilir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;languages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;))];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredRepos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matchesLang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matchesSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;matchesLang&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;matchesSearch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Arama Fonksiyonu
&lt;/h3&gt;

&lt;p&gt;Real-time arama ile repo ismi, owner veya description'da arama yapılır.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Görsel İstatistikler
&lt;/h3&gt;

&lt;p&gt;Recharts kütüphanesi ile dil dağılımı bar chart ve growth liderleri listesi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponsiveContainer&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BarChart&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;insights&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;topLanguages&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CartesianGrid&lt;/span&gt; &lt;span class="nx"&gt;strokeDasharray&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8 8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ffffff03&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;XAxis&lt;/span&gt; &lt;span class="nx"&gt;dataKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#475569&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;YAxis&lt;/span&gt; &lt;span class="nx"&gt;stroke&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#475569&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Tooltip&lt;/span&gt; &lt;span class="nx"&gt;contentStyle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rgba(15, 23, 42, 0.9)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Bar&lt;/span&gt; &lt;span class="nx"&gt;dataKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;insights&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;topLanguages&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cell&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;fill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;getLangColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;))}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Bar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/BarChart&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ResponsiveContainer&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Deployment Feed
&lt;/h3&gt;

&lt;p&gt;Her güncelleme için bir feed entry oluşturulur. Kullanıcılar deployment tarihçesini görebilir.&lt;/p&gt;




&lt;h2&gt;
  
  
  Custom Domain Ayarı
&lt;/h2&gt;

&lt;p&gt;GitHub Pages için custom domain kullanmak istersen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;CNAME dosyası oluştur&lt;/strong&gt; - &lt;code&gt;public/CNAME&lt;/code&gt; içine domain yaz:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   furkankoykiran.com.tr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;DNS ayarı&lt;/strong&gt; - Domain provider'ında:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;   &lt;span class="n"&gt;CNAME&lt;/span&gt; &lt;span class="n"&gt;furkankoykiran&lt;/span&gt;.&lt;span class="n"&gt;github&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS&lt;/strong&gt; - GitHub Pages otomatik olarak Let's Encrypt ile SSL sağlar.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Performans İpuçları
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Asset Optimization
&lt;/h3&gt;

&lt;p&gt;Vite production build otomatik olarak minification ve tree-shaking yapar. Büyük resimler için &lt;code&gt;public/&lt;/code&gt; klasörü yerine optimized image kullanın.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Lazy Loading
&lt;/h3&gt;

&lt;p&gt;Büyük listeler için virtual scrolling kullanmayı düşünün. Bu projede 25 repo olduğu için gerekli değil ama scale ederseniz eklenebilir.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Caching
&lt;/h3&gt;

&lt;p&gt;GitHub Pages otomatik olarak cache headers ekler. Ancak &lt;code&gt;index.html&lt;/code&gt; için cache-busting kullanın:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rollupOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;entryFileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`assets/[name].[hash].js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;chunkFileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`assets/[name].[hash].js`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;assetFileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`assets/[name].[hash].[ext]`&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Canlı Demo
&lt;/h2&gt;

&lt;p&gt;Proje şu anda &lt;a href="https://furkankoykiran.com.tr/awesome-trending-repos/" rel="noopener noreferrer"&gt;furkankoykiran.com.tr/awesome-trending-repos&lt;/a&gt; adresinde yayında. Her gün otomatik olarak güncelleniyor.&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%2Fzywpheil54s5wiyo2zt6.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%2Fzywpheil54s5wiyo2zt6.png" alt="Project Logo" width="640" height="640"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Proje logosu&lt;/em&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%2Fdw2qfuyhzi0xscpwksx9.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%2Fdw2qfuyhzi0xscpwksx9.png" alt="OG Image" width="640" height="336"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Open Graph preview görseli&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Sonuç
&lt;/h2&gt;

&lt;p&gt;README.md'den modern web uygulamasına geçiş, projenin kullanılabilirliğini önemli ölçüde artırdı. Kullanıcılar artık sadece statik bir liste yerine interaktif bir deneyim yaşıyor.&lt;/p&gt;

&lt;p&gt;GitHub Pages + Vite kombinasyonu, static siteler için harika bir çözüm. Ücretsiz, hızlı ve CI/CD ile tam otomatik.&lt;/p&gt;

&lt;p&gt;Proje tamamen açık kaynak. Katkı yapmak isterseniz &lt;a href="https://github.com/furkankoykiran/awesome-trending-repos" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;'ya pull request gönderebilirsiniz.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Kaynak: &lt;a href="https://blog.furkankoykiran.com.tr" rel="noopener noreferrer"&gt;blog.furkankoykiran.com.tr&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>vite</category>
      <category>github</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Adding Browser Automation to CLI-Anything: First MCP Backend Pattern</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Sun, 22 Mar 2026 22:40:08 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/adding-browser-automation-to-cli-anything-first-mcp-backend-pattern-4bb3</link>
      <guid>https://dev.to/furkankoykiran/adding-browser-automation-to-cli-anything-first-mcp-backend-pattern-4bb3</guid>
      <description>&lt;p&gt;Browser automation is genuinely interesting. AI agents navigating websites, filling forms - it's not just nice to have anymore. I recently contributed browser automation support to CLI-Anything via DOMShell's MCP server. Here's how it went.&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%2Fq8y42ejybul3qpfs2yfg.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%2Fq8y42ejybul3qpfs2yfg.png" alt="MCP Architecture" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From Issue #90 to PR #118
&lt;/h2&gt;

&lt;p&gt;On March 16, &lt;a href="https://github.com/apireno" rel="noopener noreferrer"&gt;@apireno&lt;/a&gt; opened &lt;a href="https://github.com/HKUDS/CLI-Anything/issues/90" rel="noopener noreferrer"&gt;#90&lt;/a&gt; with a compelling idea: &lt;strong&gt;"CLI wrappers make software agent-native"&lt;/strong&gt; - and this should work for browsers too.&lt;/p&gt;

&lt;p&gt;They mentioned &lt;a href="https://github.com/apireno/DOMShell" rel="noopener noreferrer"&gt;DOMShell&lt;/a&gt;, which maps Chrome's Accessibility Tree to a virtual filesystem. Agents control the browser with &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;click&lt;/code&gt; - shell commands, not DOM queries. The benchmark was solid: 50% fewer API calls than screenshot-based browsing in Claude tests.&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%2Fnxpa6rcjkqvb5zt3fkfg.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%2Fnxpa6rcjkqvb5zt3fkfg.png" alt="Accessibility Tree" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the Accessibility Tree?
&lt;/h3&gt;

&lt;p&gt;The Accessibility Tree is what the browser derives from DOM for screen readers. It's simpler, semantic. Elements are classified by role - button, link, textbox. More stable than DOM, more understandable for agents.&lt;/p&gt;

&lt;p&gt;DOMShell's insight: filesystem primitives beat DOM queries. &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt; instead of &lt;code&gt;querySelector&lt;/code&gt; and &lt;code&gt;getElementById&lt;/code&gt;. Agents explore faster, call fewer APIs.&lt;/p&gt;

&lt;p&gt;On March 21, based on &lt;a href="https://github.com/omerarslan0" rel="noopener noreferrer"&gt;@omerarslan0&lt;/a&gt;'s proposal, I created &lt;a href="https://github.com/HKUDS/CLI-Anything/pull/118" rel="noopener noreferrer"&gt;#118&lt;/a&gt;. This became CLI-Anything's &lt;strong&gt;first MCP server backend pattern&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# How it looks&lt;/span&gt;
cli-anything-browser page open https://example.com
cli-anything-browser fs &lt;span class="nb"&gt;ls&lt;/span&gt; /
cli-anything-browser fs &lt;span class="nb"&gt;cd&lt;/span&gt; /main
cli-anything-browser fs &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Login"&lt;/span&gt;
cli-anything-browser act click /main/button[0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Most CLI-Anything harnesses call backend APIs directly. This one was different: &lt;strong&gt;MCP Server integration&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Backend Pattern
&lt;/h3&gt;

&lt;p&gt;No CLI-Anything harness had used an MCP server before. The Python SDK implementation:&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;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.client.stdio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stdio_client&lt;/span&gt;

&lt;span class="n"&gt;server_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StdioServerParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@apireno/domshell&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="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;as &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;domshell_ls&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;path&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;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MCP server is &lt;strong&gt;stateless&lt;/strong&gt;. Each command spawns a new subprocess. State (URL, working directory, history) lives on the CLI side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Commands
&lt;/h3&gt;

&lt;p&gt;Four main groups: &lt;strong&gt;page&lt;/strong&gt; (open, reload, back, forward, info), &lt;strong&gt;fs&lt;/strong&gt; (ls, cd, cat, grep, pwd), &lt;strong&gt;act&lt;/strong&gt; (click, type), and &lt;strong&gt;session&lt;/strong&gt; (status, daemon-start, daemon-stop).&lt;/p&gt;

&lt;h3&gt;
  
  
  Daemon Mode
&lt;/h3&gt;

&lt;p&gt;Spawning npx for every command costs 1-3 seconds. &lt;strong&gt;Daemon mode&lt;/strong&gt; keeps a persistent connection. The difference is noticeable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-browser session daemon-start
&lt;span class="c"&gt;# All commands use the same connection now&lt;/span&gt;
cli-anything-browser fs &lt;span class="nb"&gt;ls&lt;/span&gt; /
cli-anything-browser session daemon-stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;I went with a multi-layered approach. Unit tests (31 total) mocked MCP responses, tested path resolution and state management. No Chrome required.&lt;/p&gt;

&lt;p&gt;E2E tests (10 total) needed Chrome + DOMShell extension, tested against real pages. Tests skip when DOMShell isn't installed, so CI/CD doesn't break.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review Process
&lt;/h2&gt;

&lt;p&gt;After submitting, &lt;a href="https://github.com/omerarslan0" rel="noopener noreferrer"&gt;@omerarslan0&lt;/a&gt; did a thorough review. I got 9 feedback items. The critical ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daemon mode context manager leak&lt;/strong&gt; - Fixed with &lt;code&gt;_daemon_client_context&lt;/code&gt; global&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;go_back()/go_forward()&lt;/strong&gt; - Switched from local history to native MCP tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REPL quoted arguments&lt;/strong&gt; - Fixed with &lt;code&gt;shlex.split()&lt;/code&gt;, quoted arguments parse correctly now&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; - &lt;code&gt;act type&lt;/code&gt; no longer echoes typed text, passwords don't leak into terminal scrollback&lt;/li&gt;
&lt;/ul&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%2Fkes31aup1kj9ny5fnsrq.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%2Fkes31aup1kj9ny5fnsrq.png" alt="Browser CLI Interface" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge
&lt;/h2&gt;

&lt;p&gt;The PR merged on March 22. 3,095 additions, 21 files changed, 15 commits. This became CLI-Anything's reference implementation for MCP backend patterns - a template for future integrations.&lt;/p&gt;

&lt;p&gt;The browser harness went into CLI-Hub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"browser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Browser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Browser automation via DOMShell MCP server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requires"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Node.js, npx, Chrome + DOMShell extension"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"homepage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/apireno/DOMShell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"install_cmd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=browser/agent-harness"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"entry_point"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cli-anything-browser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contributor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"furkankoykiran"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;strong&gt;MCP Python SDK&lt;/strong&gt;: &lt;code&gt;stdio&lt;/code&gt; transport with subprocess, async-to-sync wrapper, tool calling patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility Tree vs DOM&lt;/strong&gt;: More stable, less fragile, ideal for agents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open Source&lt;/strong&gt;: Issue to implementation, managing review feedback, documentation, test coverage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Daemon Mode&lt;/strong&gt;: Context manager lifecycle, state persistence, event loop limitations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future
&lt;/h2&gt;

&lt;p&gt;I left out of V1: screenshot capture, wait-for-element, form fill helper, headless mode, multi-browser (Firefox, Safari), concurrent MCP operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/apireno" rel="noopener noreferrer"&gt;@apireno&lt;/a&gt; suggested &lt;code&gt;eval&lt;/code&gt; and &lt;code&gt;js&lt;/code&gt; escape hatches for when elements don't have clean AX representations - good additions for a follow-up.&lt;/p&gt;

&lt;p&gt;This contribution did more than add browser automation to CLI-Anything. It established a pattern for MCP server integrations. The "MCP Backend Pattern" section I added to &lt;code&gt;cli-anything-plugin/HARNESS.md&lt;/code&gt; will guide other developers.&lt;/p&gt;

&lt;p&gt;Implementing a new pattern in open source is interesting work. The feedback from &lt;a href="https://github.com/omerarslan0" rel="noopener noreferrer"&gt;@omerarslan0&lt;/a&gt;, &lt;a href="https://github.com/yuh-yang" rel="noopener noreferrer"&gt;@yuh-yang&lt;/a&gt;, and &lt;a href="https://github.com/apireno" rel="noopener noreferrer"&gt;@apireno&lt;/a&gt; during review made this better.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/HKUDS/CLI-Anything/issues/90" rel="noopener noreferrer"&gt;Issue #90&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HKUDS/CLI-Anything/pull/118" rel="noopener noreferrer"&gt;PR #118&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/apireno/DOMShell" rel="noopener noreferrer"&gt;DOMShell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HKUDS/CLI-Anything" rel="noopener noreferrer"&gt;CLI-Anything&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This post was submitted to DEV.to via &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
      <category>mcp</category>
      <category>browserautomation</category>
    </item>
    <item>
      <title>CLI-Anything'e Tarayıcı Otomasyon Desteği: MCP Backend Pattern İlk Uygulama</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Sun, 22 Mar 2026 22:40:06 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/cli-anythinge-tarayici-otomasyon-destegi-mcp-backend-pattern-ilk-uygulama-221d</link>
      <guid>https://dev.to/furkankoykiran/cli-anythinge-tarayici-otomasyon-destegi-mcp-backend-pattern-ilk-uygulama-221d</guid>
      <description>&lt;p&gt;Tarayıcı otomasyonu gerçekten ilginç bir problem. AI ajanlarının web sitelerinde gezinebilmesi, formları doldurabilmesi artık sadece "iyi sahip olmak" değil, zorunluluk. CLI-Anything projesine yaptığım browser support katkısını burada anlatacağım.&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%2Fq8y42ejybul3qpfs2yfg.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%2Fq8y42ejybul3qpfs2yfg.png" alt="MCP Architecture" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue #90'dan PR #118'e
&lt;/h2&gt;

&lt;p&gt;Her şey 16 Mart 2026'da &lt;a href="https://github.com/apireno" rel="noopener noreferrer"&gt;@apireno&lt;/a&gt;'nin &lt;a href="https://github.com/HKUDS/CLI-Anything/issues/90" rel="noopener noreferrer"&gt;#90 numaralı issue&lt;/a&gt;'sını açmasıyla başladı. Ana fikir şuydu: &lt;strong&gt;"CLI wrapper'lar yazılımı ajan-native yapıyor"&lt;/strong&gt; ve bunun tarayıcılar için de geçerli olabileceği.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/apireno" rel="noopener noreferrer"&gt;@apireno&lt;/a&gt;, &lt;a href="https://github.com/apireno/DOMShell" rel="noopener noreferrer"&gt;DOMShell&lt;/a&gt; projesinden bahsetti. DOMShell, Chrome'un Accessibility Tree'sini sanal bir dosya sistemine çeviriyor. Ajanlar &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;click&lt;/code&gt; gibi komutlarla tarayıcıyı kontrol edebiliyor. Benchmark sonuçları ilginçti: screenshot tabanlı yaklaşıma göre %50 daha az API çağrısı.&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%2Fnxpa6rcjkqvb5zt3fkfg.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%2Fnxpa6rcjkqvb5zt3fkfg.png" alt="Accessibility Tree" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessibility Tree Nedir?
&lt;/h3&gt;

&lt;p&gt;Accessibility Tree, tarayıcının DOM'dan ürettiği ama daha sade bir yapı. Ekran okuyucular için var bu yapı. Öğeleri rollerine göre sınıflandırıyor - button, link, textbox gibi. Ajanlar için de ideal aslında, stabil ve anlaşılır.&lt;/p&gt;

&lt;p&gt;DOMShell'in mantığı basitti: &lt;strong&gt;Filesystem primitives&lt;/strong&gt; (ls, cd, grep) DOM query'lerden daha verimli. Ajanlar sayfayı gezerken daha az çağrı yapıyor, daha hızlı ulaşıyor hedefe.&lt;/p&gt;

&lt;p&gt;21 Mart'ta &lt;a href="https://github.com/omerarslan0" rel="noopener noreferrer"&gt;@omerarslan0&lt;/a&gt;'nın önerdiği modeli temel alarak PR'ı oluşturdum. Bu, CLI-Anything'in ilk MCP server backend pattern'idi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Kullanım örneği&lt;/span&gt;
cli-anything-browser page open https://example.com
cli-anything-browser fs &lt;span class="nb"&gt;ls&lt;/span&gt; /
cli-anything-browser fs &lt;span class="nb"&gt;cd&lt;/span&gt; /main
cli-anything-browser fs &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Login"&lt;/span&gt;
cli-anything-browser act click /main/button[0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mimari
&lt;/h2&gt;

&lt;p&gt;Diğer harness'lar genellikle doğrudan backend API çağrısı yapıyor. Bu sefer durum farklıydı: &lt;strong&gt;MCP Server&lt;/strong&gt; entegrasyonu.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Backend Pattern
&lt;/h3&gt;

&lt;p&gt;Bu CLI-Anything için yeni bir patterndi. Öncesinde hiçbir harness MCP server kullanmamıştı. Python SDK implementasyonu:&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;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.client.stdio&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stdio_client&lt;/span&gt;

&lt;span class="n"&gt;server_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StdioServerParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@apireno/domshell&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="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;stdio_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;as &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;domshell_ls&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;path&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;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ana fark şu: MCP server &lt;strong&gt;stateless&lt;/strong&gt;. Her komutta yeni subprocess başlıyor. State (URL, working directory, history) CLI tarafında tutuluyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Command Groups
&lt;/h3&gt;

&lt;p&gt;Implementasyon 4 ana group içeriyordu:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;page&lt;/strong&gt;: open, reload, back, forward, info - Sayfa navigasyonu&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;fs&lt;/strong&gt;: ls, cd, cat, grep, pwd - Dosya sistemi tarzı gezinme&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;act&lt;/strong&gt;: click, type - Etkileşim&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;session&lt;/strong&gt;: status, daemon-start, daemon-stop - Oturum yönetimi&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Daemon Mode
&lt;/h3&gt;

&lt;p&gt;Her komutta npx subprocess başlatmak 1-3 saniye kaybettiriyor. &lt;strong&gt;Daemon mode&lt;/strong&gt; ile kalıcı bağlantı kuruyorsun. İnteraktif kullanımda fark hissediliyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testler
&lt;/h2&gt;

&lt;p&gt;Üç katmanlı test stratejisi uyguladım. Unit tests 31 taneydi - MCP backend response'ları mock'lanıyor, path resolution ve state management test ediliyordu. Chrome gerekmiyordu.&lt;/p&gt;

&lt;p&gt;E2E tests 10 taneydi. Chrome + DOMShell extension gerekiyordu. Gerçek sayfalarda test ediyordu. DOMShell yoksa testler skip oluyordu, böylece CI/CD patlamıyordu.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review Süreci
&lt;/h2&gt;

&lt;p&gt;PR'ı gönderdikten sonra &lt;a href="https://github.com/omerarslan0" rel="noopener noreferrer"&gt;@omerarslan0&lt;/a&gt; review yaptı. 9 maddelik feedback aldım. En kritikleri:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daemon mode context manager leak&lt;/strong&gt; - &lt;code&gt;_daemon_client_context&lt;/code&gt; global değişkeni ile düzeltildi&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;go_back()/go_forward()&lt;/strong&gt; - Native MCP tool'ları kullanıldı&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REPL quoted arguments&lt;/strong&gt; - &lt;code&gt;shlex.split()&lt;/code&gt; ile düzeltildi, tırnaklı argümanlar artık doğru parse ediliyor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; - &lt;code&gt;act type&lt;/code&gt; artık typed text'i echo etmiyor, passwordler terminal scrollback'de kalmıyor&lt;/li&gt;
&lt;/ul&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%2Fkes31aup1kj9ny5fnsrq.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%2Fkes31aup1kj9ny5fnsrq.png" alt="Browser CLI Interface" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Merge ve Sonuç
&lt;/h2&gt;

&lt;p&gt;22 Mart'ta PR merge edildi. 3,095 satır ekleme, 21 dosya değişti, 15 commit. Bu, CLI-Anything'in ilk MCP backend pattern referans implementasyonu. Gelecekteki MCP entegrasyonları için bir template olacak.&lt;/p&gt;

&lt;p&gt;Browser harness CLI-Hub'a eklendi ve artık kullanıma hazır.&lt;/p&gt;

&lt;h2&gt;
  
  
  Öğrendiklerim
&lt;/h2&gt;

&lt;h3&gt;
  
  
  MCP Python SDK
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;stdio&lt;/code&gt; transport ile subprocess communication, async → sync wrapper, tool calling pattern'leri.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessibility Tree vs DOM
&lt;/h3&gt;

&lt;p&gt;Accessibility Tree daha stabil. DOM query'lerden daha az kırılgan. Agent navigation için ideal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Source
&lt;/h3&gt;

&lt;p&gt;Issue'dan implementasyona geçiş, review feedback yönetimi, documentation update'leri, test coverage önemi.&lt;/p&gt;

&lt;p&gt;Bu katkı sadece bir browser harness değil, aynı zamanda gelecekteki MCP entegrasyonları için bir referans pattern oluşturdu. &lt;code&gt;cli-anything-plugin/HARNESS.md&lt;/code&gt;'ye eklenen MCP Backend Pattern bölümü, diğer geliştiricilere rehber olacak.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/HKUDS/CLI-Anything/issues/90" rel="noopener noreferrer"&gt;Issue #90&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HKUDS/CLI-Anything/pull/118" rel="noopener noreferrer"&gt;PR #118&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/apireno/DOMShell" rel="noopener noreferrer"&gt;DOMShell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HKUDS/CLI-Anything" rel="noopener noreferrer"&gt;CLI-Anything&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Bu yazı &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt; aracılığıyla DEV.to'ya gönderilmiştir.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
      <category>mcp</category>
      <category>browserautomation</category>
    </item>
    <item>
      <title>My Keploy Contribution: Resource Management in Go and Open Source Journey</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Sat, 21 Mar 2026 00:27:26 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/my-keploy-contribution-resource-management-in-go-and-open-source-journey-2139</link>
      <guid>https://dev.to/furkankoykiran/my-keploy-contribution-resource-management-in-go-and-open-source-journey-2139</guid>
      <description>&lt;p&gt;While tracking popular repositories on GitHub trending with my &lt;a href="https://github.com/furkankoykiran/awesome-trending-repos" rel="noopener noreferrer"&gt;awesome-trending-repos&lt;/a&gt; project, I came across &lt;a href="https://github.com/keploy/keploy" rel="noopener noreferrer"&gt;Keploy&lt;/a&gt;, a modern API testing tool written in Go. While exploring the codebase, I found a couple of resource management bugs that I could fix.&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%2Fblog.furkankoykiran.com.tr%2Fassets%2Fimg%2Fposts%2F2026-03-20-keploy%2Fhow-keploy-works.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%2Fblog.furkankoykiran.com.tr%2Fassets%2Fimg%2Fposts%2F2026-03-20-keploy%2Fhow-keploy-works.png" alt="Keploy Architecture" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Keploy is a modern tool for automated testing and mock generation for APIs, Integration, and E2E tests.&lt;/em&gt;&lt;/p&gt;


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

&lt;p&gt;Keploy is an open-source tool for API and integration testing. It provides features like mock creation and test generation, and has over 8k stars on GitHub. It integrates with VSCode through an extension.&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%2Fblog.furkankoykiran.com.tr%2Fassets%2Fimg%2Fposts%2F2026-03-20-keploy%2Fkeploy-vscode-extension.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%2Fblog.furkankoykiran.com.tr%2Fassets%2Fimg%2Fposts%2F2026-03-20-keploy%2Fkeploy-vscode-extension.png" alt="Keploy VSCode Extension" width="800" height="539"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The VSCode extension allows Keploy to manage tests and mocks directly from the IDE.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While examining the codebase, I noticed some common resource management mistakes in Go. I fixed these issues with two separate PRs.&lt;/p&gt;


&lt;h2&gt;
  
  
  PR #3927: The Use-After-Close Bug
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Discovering the Problem
&lt;/h3&gt;

&lt;p&gt;While browsing the project's GitHub issues, I came across &lt;a href="https://github.com/keploy/keploy/issues/3821" rel="noopener noreferrer"&gt;#3821&lt;/a&gt;, which reported a bug in the &lt;code&gt;isGoBinary&lt;/code&gt; function in &lt;code&gt;utils/utils.go&lt;/code&gt;. The file was being opened and immediately closed, then operations were performed on the closed file.&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="c"&gt;// BUGGY CODE&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;elf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to open file %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c"&gt;// ❌ Closed immediately&lt;/span&gt;
    &lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to close file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Then operating on the closed file&lt;/span&gt;
&lt;span class="n"&gt;sections&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;".go.buildinfo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".gopclntab"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;sections&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;sect&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c"&gt;// ❌ Use-after-close&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This causes what's known as a "use-after-close" error in Go. After the file is closed, the file descriptor is no longer valid.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution: Defer Pattern
&lt;/h3&gt;

&lt;p&gt;In Go, the &lt;code&gt;defer&lt;/code&gt; pattern is used to solve this problem. A statement prefixed with &lt;code&gt;defer&lt;/code&gt; is executed just before the function returns. This ensures that the resource is cleaned up regardless of how the function exits (early return, panic, or normal return).&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="c"&gt;// FIXED CODE&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;elf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to open file %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to close file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="c"&gt;// File is now open, can read sections&lt;/span&gt;
&lt;span class="n"&gt;sections&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;".go.buildinfo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".gopclntab"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;sections&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;sect&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code Review Feedback
&lt;/h3&gt;

&lt;p&gt;I received feedback from the Copilot code reviewer. Using &lt;code&gt;defer f.Close()&lt;/code&gt; directly would ignore the error returned by &lt;code&gt;Close()&lt;/code&gt;. This didn't match the pattern used elsewhere in the repository.&lt;/p&gt;

&lt;p&gt;I addressed the feedback by wrapping the defer in a closure and adding error handling:&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="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to close file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/keploy/keploy/pull/3927" rel="noopener noreferrer"&gt;PR #3927&lt;/a&gt; was successfully merged.&lt;/p&gt;




&lt;h2&gt;
  
  
  PR #3932: HTTP Response Body Leak
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Discovering the Problem
&lt;/h3&gt;

&lt;p&gt;I found issue &lt;a href="https://github.com/keploy/keploy/issues/3854" rel="noopener noreferrer"&gt;#3854&lt;/a&gt; on the project's tracker, which reported that in &lt;code&gt;pkg/platform/http/agent.go&lt;/code&gt;, the &lt;code&gt;MockOutgoing&lt;/code&gt; and &lt;code&gt;UpdateMockParams&lt;/code&gt; functions were not closing HTTP response bodies after making requests.&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="c"&gt;// BUGGY CODE&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to send request: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Body not closed! ❌&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockResp&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AgentResp&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&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;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mockResp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This leads to several problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Resource Leak&lt;/strong&gt;: Unclosed bodies cause memory leaks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection Pool Exhaustion&lt;/strong&gt;: The HTTP client's connection pool gets exhausted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port Exhaustion&lt;/strong&gt;: Many open connections can consume system ports&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Solution: Defer Close + Drain Pattern
&lt;/h3&gt;

&lt;p&gt;Go's &lt;code&gt;http&lt;/code&gt; package documentation states that the caller is responsible for closing the response body. If the body is not closed, the underlying TCP connection cannot be returned to the connection pool, and a new connection must be created for each request.&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="c"&gt;// FIXED CODE&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to send request: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// Drain body to EOF&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to close response body"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockResp&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AgentResp&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&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;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mockResp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we do two important things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;io.Copy(io.Discard, res.Body)&lt;/code&gt;&lt;/strong&gt;: We read and discard the body until EOF. This allows the connection to be reused because the JSON decoder might not have read the entire body.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;res.Body.Close()&lt;/code&gt;&lt;/strong&gt;: We close the body and log any errors.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why Drain the Body?
&lt;/h3&gt;

&lt;p&gt;An important detail I learned from the Copilot reviewer: &lt;code&gt;json.Decoder.Decode()&lt;/code&gt; doesn't guarantee reading the entire body. If there are unread bytes in the body and we close it directly, the HTTP client cannot reuse the connection (keep-alive won't work).&lt;/p&gt;

&lt;p&gt;By draining the body with &lt;code&gt;io.Copy(io.Discard, res.Body)&lt;/code&gt; to EOF, the connection can be returned to the pool for reuse.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/keploy/keploy/pull/3932" rel="noopener noreferrer"&gt;PR #3932&lt;/a&gt; was successfully merged.&lt;/p&gt;




&lt;h2&gt;
  
  
  Go Resource Management Best Practices
&lt;/h2&gt;

&lt;p&gt;These two PRs taught me important lessons about resource management in Go:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Using the Defer Pattern
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// File operations&lt;/span&gt;
&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file.txt"&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// Mutex locking&lt;/span&gt;
&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// Database transaction&lt;/span&gt;
&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Begin&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c"&gt;// Rollback if not committed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Error Handling in Defer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ❌ Error is ignored&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// ✅ Error is handled&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"close error: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. HTTP Connection Reuse
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ❌ Connection cannot be reused&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// ✅ Connection returns to pool&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Defer Execution Order
&lt;/h3&gt;

&lt;p&gt;Defer statements execute in LIFO (Last In, First Out) order:&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="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// Last: "1"&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// Second: "2"&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// First: "3"&lt;/span&gt;
&lt;span class="c"&gt;// Output: 3, 2, 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;From this open source contribution process, I learned:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;Lesson Learned&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Go Defer Pattern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Using defer for resource cleanup, error handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP Connection Pooling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Draining response body, connection reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Review&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Improving code quality with Copilot feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Open Source Communication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Writing PR descriptions, communicating with maintainers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The maintainers' code reviews were very educational. I received detailed feedback on code style, edge cases, and error handling.&lt;/p&gt;




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

&lt;p&gt;My two small contributions to the Keploy project gave me practical knowledge about resource management in Go. Subtle bugs like use-after-close and HTTP response leaks can cause major problems in production.&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%2Fblog.furkankoykiran.com.tr%2Fassets%2Fimg%2Fposts%2F2026-03-20-keploy%2Fkeploy-logo.svg" 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%2Fblog.furkankoykiran.com.tr%2Fassets%2Fimg%2Fposts%2F2026-03-20-keploy%2Fkeploy-logo.svg" alt="Keploy Logo" width="654" height="211"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Keploy is an open-source project open to contributions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Contributing to open source is not just about writing code, it's also about interacting with the community and learning. Every PR adds value to both the project and yourself.&lt;/p&gt;

&lt;p&gt;If you want to learn more about resource management in Go, I recommend checking out &lt;a href="https://go.dev/doc/effective_go" rel="noopener noreferrer"&gt;Effective Go&lt;/a&gt; and &lt;a href="https://github.com/golang/go/wiki/CommonMistakes" rel="noopener noreferrer"&gt;Common Mistakes in Go&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Related Posts:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.furkankoykiran.com.tr/posts/awesome-trending-repos-en/" rel="noopener noreferrer"&gt;awesome-trending-repos: GitHub Trending Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.furkankoykiran.com.tr/posts/github-mcp-server-acik-kaynak-katki/" rel="noopener noreferrer"&gt;GitHub MCP Server Project Contribution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.furkankoykiran.com.tr/posts/mcp-ai-contributions/" rel="noopener noreferrer"&gt;My MCP Ecosystem Contributions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This post was published to DEV.to via &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>keploy</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Keploy'a Katkılarım: Go'da Resource Management ve Open Source Serüveni</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Sat, 21 Mar 2026 00:27:24 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/keploya-katkilarim-goda-resource-management-ve-open-source-seruveni-27lb</link>
      <guid>https://dev.to/furkankoykiran/keploya-katkilarim-goda-resource-management-ve-open-source-seruveni-27lb</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/furkankoykiran/awesome-trending-repos" rel="noopener noreferrer"&gt;awesome-trending-repos&lt;/a&gt; projem ile GitHub trending'deki popüler repoları takip ederken, Go ile yazılmış modern bir API testing aracı olan &lt;a href="https://github.com/keploy/keploy" rel="noopener noreferrer"&gt;Keploy&lt;/a&gt; dikkatimi çekti. Kod tabanını incelerken düzeltebileceğim birkaç resource management bug'ı buldum.&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%2Fi0etkyvkteojeo61eg0w.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%2Fi0etkyvkteojeo61eg0w.png" alt="Keploy Architecture" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Keploy, API, Integration ve E2E testing için otomatik test ve mock oluşturabilen modern bir araç.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Keploy Nedir?
&lt;/h2&gt;

&lt;p&gt;Keploy, API ve entegrasyon testing için geliştirilmiş açık kaynak bir araç. Mock oluşturma, test generation gibi özellikler sunuyor ve GitHub'da 8k+ yıldızı var. VSCode extension ile entegre çalışabiliyor.&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%2Fsi128wz19lf5tcy7nj29.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%2Fsi128wz19lf5tcy7nj29.png" alt="Keploy VSCode Extension" width="800" height="539"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;VSCode extension ile Keploy, IDE içinden test ve mock yönetimi sağlıyor.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Projeyi incelerken Go'da sık yapılan resource management hatalarını fark ettim. İki farklı PR ile bu sorunları çözdüm.&lt;/p&gt;


&lt;h2&gt;
  
  
  PR #3927: Use-After-Close Bug'ı
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Problemi Keşfetmek
&lt;/h3&gt;

&lt;p&gt;Projenin GitHub issue'larını incelerken, &lt;a href="https://github.com/keploy/keploy/issues/3821" rel="noopener noreferrer"&gt;#3821 numaralı issue&lt;/a&gt;'de raporlanan bir sorunu fark ettim. &lt;code&gt;utils/utils.go&lt;/code&gt; dosyasındaki &lt;code&gt;isGoBinary&lt;/code&gt; fonksiyonunda, dosya açılıp hemen kapatılıyor, sonra kapatılmış dosya üzerinde section okuma işlemi yapılıyordu.&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="c"&gt;// HATALI KOD&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;elf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to open file %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c"&gt;// ❌ Hemen kapatılıyor&lt;/span&gt;
    &lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to close file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Sonra kapatılmış dosya üzerinde işlem yapılıyor&lt;/span&gt;
&lt;span class="n"&gt;sections&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;".go.buildinfo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".gopclntab"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;sections&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;sect&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c"&gt;// ❌ Use-after-close&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu, Go'da "use-after-close" olarak bilinen bir hataya yol açar. Dosya kapatıldıktan sonra dosya tanımlayıcısı (file descriptor) artık geçerli değildir.&lt;/p&gt;

&lt;h3&gt;
  
  
  Çözüm: Defer Pattern
&lt;/h3&gt;

&lt;p&gt;Go'da bu sorunu çözmek için &lt;code&gt;defer&lt;/code&gt; pattern'i kullanılır. &lt;code&gt;defer&lt;/code&gt; ile belirtilen ifade, fonksiyon return olmadan hemen önce çalıştırılır. Bu sayede kaynak, fonksiyon ne şekilde sonlanırsa sonlansın (early return, panic, normal return) garanti olarak kapatılır.&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="c"&gt;// DÜZELTİLMİŞ KOD&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;elf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to open file %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to close file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="c"&gt;// Artık dosya açık, section okuma yapılabilir&lt;/span&gt;
&lt;span class="n"&gt;sections&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;".go.buildinfo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".gopclntab"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;sections&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;sect&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;sect&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code Review Feedback
&lt;/h3&gt;

&lt;p&gt;Copilot code reviewer'dan bir feedback aldım. &lt;code&gt;defer f.Close()&lt;/code&gt; şeklinde doğrudan kullanımda, Close() tarafından dönen error ignore ediliyordu. Bu da repository'deki diğer yerlerde kullanılan pattern'e uymuyordu.&lt;/p&gt;

&lt;p&gt;Feedback'i ele alarak defer'i bir closure içine aldım ve error handling'i ekledim:&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="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to close file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/keploy/keploy/pull/3927" rel="noopener noreferrer"&gt;PR #3927&lt;/a&gt; başarıyla merge edildi.&lt;/p&gt;




&lt;h2&gt;
  
  
  PR #3932: HTTP Response Body Leak
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problemi Keşfetmek
&lt;/h3&gt;

&lt;p&gt;Projenin issue tracker'ında, &lt;a href="https://github.com/keploy/keploy/issues/3854" rel="noopener noreferrer"&gt;#3854 numaralı issue&lt;/a&gt; ile raporlanan bir sorun tespit ettim. &lt;code&gt;pkg/platform/http/agent.go&lt;/code&gt; dosyasında &lt;code&gt;MockOutgoing&lt;/code&gt; ve &lt;code&gt;UpdateMockParams&lt;/code&gt; fonksiyonlarında HTTP request yapıldıktan sonra response body kapatılmıyordu.&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="c"&gt;// HATALI KOD&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to send request: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Body kapatılmıyor! ❌&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockResp&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AgentResp&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&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;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mockResp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu durum birkaç soruna yol açar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Resource Leak&lt;/strong&gt;: Açık kalan body'ler memory leak'e neden olur&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection Pool Exhaustion&lt;/strong&gt;: HTTP client'ının connection pool'u tükenir&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port Exhaustion&lt;/strong&gt;: Çok sayıda açık connection, sistem portlarını tüketebilir&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Çözüm: Defer Close + Drain Pattern
&lt;/h3&gt;

&lt;p&gt;Go'nun &lt;code&gt;http&lt;/code&gt; package'i, response body'yi kapatmak için çağıranın sorumlu olduğunu belirtir. Body kapatılmazsa, underlying TCP connection connection pool'a geri dönmez ve yeni bir connection oluşturulması gerekir.&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="c"&gt;// DÜZELTİLMİŞ KOD&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to send request: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// Body'yi EOF'a kadar drain et&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to close response body"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockResp&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AgentResp&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&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;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mockResp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Burada iki önemli işlem yapıyoruz:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;io.Copy(io.Discard, res.Body)&lt;/code&gt;&lt;/strong&gt;: Body'yi EOF'a kadar okuyup discard ediyoruz. Bu, connection'ın reuse edilmesini sağlar çünkü JSON decoder tüm body'yi okumamış olabilir.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;res.Body.Close()&lt;/code&gt;&lt;/strong&gt;: Body'yi kapatıyoruz ve error'u logluyoruz.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Neden Drain Ediyoruz?
&lt;/h3&gt;

&lt;p&gt;Copilot reviewer'dan öğrendiğim önemli bir detay: &lt;code&gt;json.Decoder.Decode()&lt;/code&gt; tüm body'yi okumama garantisi vermez. Eğer body'de okunmamış byte'lar kalırsa ve direkt kapatırsak, HTTP client connection'ı yeniden kullanamaz (keep-alive çalışmaz).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;io.Copy(io.Discard, res.Body)&lt;/code&gt; ile body'yi EOF'a kadar drain ediyoruz, böylece connection pool'a geri dönülebilir.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/keploy/keploy/pull/3932" rel="noopener noreferrer"&gt;PR #3932&lt;/a&gt; başarıyla merge edildi.&lt;/p&gt;




&lt;h2&gt;
  
  
  Go'da Resource Management Best Practices
&lt;/h2&gt;

&lt;p&gt;Bu iki PR ile Go'da resource management hakkında önemli dersler öğrendim:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Defer Pattern Kullanımı
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Dosya işlemleri&lt;/span&gt;
&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file.txt"&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// Mutex kilitleme&lt;/span&gt;
&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// Database transaction&lt;/span&gt;
&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Begin&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c"&gt;// Commit olmazsa rollback&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Defer'de Error Handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ❌ Error ignore edilir&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// ✅ Error handle edilir&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"close error: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. HTTP Connection Reuse
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ❌ Connection yeniden kullanılamaz&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// ✅ Connection pool'a geri döner&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Defer Execution Order
&lt;/h3&gt;

&lt;p&gt;Defer statements LIFO (Last In, First Out) sırasıyla çalışır:&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="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// Son: "1"&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// İkinci: "2"&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// İlk: "3"&lt;/span&gt;
&lt;span class="c"&gt;// Çıktı: 3, 2, 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Öğrendiklerim
&lt;/h2&gt;

&lt;p&gt;Bu açık kaynak katkısı sürecinden öğrendiklerim:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Konu&lt;/th&gt;
&lt;th&gt;Öğrenilen Ders&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Go Defer Pattern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Resource cleanup için defer kullanımı, error handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP Connection Pooling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Response body drain etmek, connection reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Review&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Copilot feedback'i ile code kalitesini artırmak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Open Source Communication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;PR description yazma, maintainer ile iletişim&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Maintainer'ların code review'leri çok öğreticiydi. Kod stili, edge case'ler ve error handling hakkında detaylı feedback aldım.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sonuç
&lt;/h2&gt;

&lt;p&gt;Keploy projesine yaptığım bu iki küçük katkı, bana Go'da resource management konusunda pratik bilgi kazandırdı. Use-after-close ve HTTP response leak gibi subtle bug'lar, production'da büyük sorunlara yol açabilir.&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%2Fblog.furkankoykiran.com.tr%2Fassets%2Fimg%2Fposts%2F2026-03-20-keploy%2Fkeploy-logo.svg" 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%2Fblog.furkankoykiran.com.tr%2Fassets%2Fimg%2Fposts%2F2026-03-20-keploy%2Fkeploy-logo.svg" alt="Keploy Logo" width="654" height="211"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Keploy açık kaynak bir proje olarak katkılara açık.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Açık kaynak dünyasına katkı vermek sadece kod yazmak değil, aynı zamanda community ile etkileşim kurmak ve öğrenmek demek. Her PR, hem projeye hem de kendinize değer katar.&lt;/p&gt;

&lt;p&gt;Eğer siz de Go'da resource management hakkında daha fazla bilgi edinmek isterseniz, &lt;a href="https://go.dev/doc/effective_go" rel="noopener noreferrer"&gt;Effective Go&lt;/a&gt; ve &lt;a href="https://github.com/golang/go/wiki/CommonMistakes" rel="noopener noreferrer"&gt;Common Mistakes in Go&lt;/a&gt; sayfalarını incelemenizi öneriyorum.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Benzer Yazılar:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.furkankoykiran.com.tr/posts/awesome-trending-repos/" rel="noopener noreferrer"&gt;awesome-trending-repos: GitHub Trending Takip Sistemi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.furkankoykiran.com.tr/posts/github-mcp-server-acik-kaynak-katki/" rel="noopener noreferrer"&gt;GitHub MCP Server Projesine Katkı&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.furkankoykiran.com.tr/posts/mcp-ai-contributions/" rel="noopener noreferrer"&gt;MCP Ekosistemi Katkılarım&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Bu yazı &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt; aracılığıyla DEV.to'ya gönderilmiştir.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>keploy</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>awesome-trending-repos: Auto-Tracking GitHub Trending</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Tue, 17 Mar 2026 21:37:56 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/awesome-trending-repos-auto-tracking-github-trending-1afj</link>
      <guid>https://dev.to/furkankoykiran/awesome-trending-repos-auto-tracking-github-trending-1afj</guid>
      <description>&lt;p&gt;Every day, hundreds of new projects appear on GitHub's trending list. However, tracking these projects and determining which ones are truly important can be time-consuming. To solve this problem, I developed the &lt;a href="https://github.com/furkankoykiran/awesome-trending-repos" rel="noopener noreferrer"&gt;awesome-trending-repos&lt;/a&gt; project.&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%2Frjvid897tnn6ob4yg8i9.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%2Frjvid897tnn6ob4yg8i9.png" alt="GitHub Actions" width="800" height="367"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Daily automated updates with GitHub Actions&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Project?
&lt;/h2&gt;

&lt;p&gt;awesome-trending-repos is an automatically updated list that tracks projects from GitHub's trending page daily. The project runs every day at midnight UTC, analyzes trending repos, and writes the results to the README.md file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔄 Daily automatic updates&lt;/li&gt;
&lt;li&gt;📊 Historical comparisons and ranking changes&lt;/li&gt;
&lt;li&gt;📈 ASCII charts and trend visualizations&lt;/li&gt;
&lt;li&gt;🏆 Fastest growing repositories (rising stars)&lt;/li&gt;
&lt;li&gt;💾 7-day historical data storage&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Does It Work?
&lt;/h2&gt;

&lt;p&gt;The project runs automatically using GitHub Actions. Every day at midnight (UTC), a workflow is triggered, scrapes the GitHub trending page, analyzes the data, and writes the results to the README.md file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data collection process:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scrape GitHub trending page (with Cheerio)&lt;/li&gt;
&lt;li&gt;Get additional data from GitHub Search API (as fallback)&lt;/li&gt;
&lt;li&gt;Categorize projects by programming language&lt;/li&gt;
&lt;li&gt;Compare with historical data&lt;/li&gt;
&lt;li&gt;Automatically update README.md&lt;/li&gt;
&lt;/ol&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%2Frjvid897tnn6ob4yg8i9.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%2Frjvid897tnn6ob4yg8i9.png" alt="GitHub Actions" width="800" height="367"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Automatic workflow management with CI/CD pipeline&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Daily Automation
&lt;/h3&gt;

&lt;p&gt;It runs automatically every day using GitHub Actions. No manual operation required. The system pulls trending data every day at midnight UTC and updates README.md.&lt;/p&gt;

&lt;h3&gt;
  
  
  Historical Tracking
&lt;/h3&gt;

&lt;p&gt;The project stores the last 7 days of data. This way you can see how a project's position in the trending list has changed. It provides detailed information about new entries, rising projects, and declining ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Language-Based Ranking
&lt;/h3&gt;

&lt;p&gt;It categorizes trending projects by programming language. You can track projects in popular languages like JavaScript, Python, TypeScript, Go, Rust separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visualization
&lt;/h3&gt;

&lt;p&gt;With ASCII charts, you can visually track the rise and fall of projects. You can see from the charts how many stars projects have received and how fast they're growing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Details
&lt;/h2&gt;

&lt;p&gt;The project is written in Node.js and uses ES Modules. It was automated with GitHub Actions and integrated with GitHub API using the Octokit library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technologies used:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 20+&lt;/li&gt;
&lt;li&gt;GitHub Actions (cron-based scheduling)&lt;/li&gt;
&lt;li&gt;Octokit (GitHub API client)&lt;/li&gt;
&lt;li&gt;Cheerio (web scraping)&lt;/li&gt;
&lt;li&gt;Axios (HTTP requests)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;With the awesome-trending-repos project, you can automatically track trending projects on GitHub. With the daily updated list, you won't miss the newest and most popular projects.&lt;/p&gt;

&lt;p&gt;The project creates a valuable resource both for personal use and for the developer community. It saves time through automation and makes tracking trends easier.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was submitted to DEV.to via &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>automation</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>awesome-trending-repos: GitHub Trending'i Otomatik Takip Etme</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Tue, 17 Mar 2026 21:37:40 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/awesome-trending-repos-github-trendingi-otomatik-takip-etme-eb2</link>
      <guid>https://dev.to/furkankoykiran/awesome-trending-repos-github-trendingi-otomatik-takip-etme-eb2</guid>
      <description>&lt;p&gt;GitHub'ta her gün yüzlerce yeni proje trending listesine giriyor. Ancak bu projeleri takip etmek, hangilerinin gerçekten önemli olduğunu belirlemek zaman alıcı bir iş. Bu sorunu çözmek için &lt;a href="https://github.com/furkankoykiran/awesome-trending-repos" rel="noopener noreferrer"&gt;awesome-trending-repos&lt;/a&gt; projesini geliştirdim.&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%2Frjvid897tnn6ob4yg8i9.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%2Frjvid897tnn6ob4yg8i9.png" alt="GitHub Actions" width="800" height="367"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;GitHub Actions ile otomatik günlük güncellemeler&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Proje Nedir?
&lt;/h2&gt;

&lt;p&gt;awesome-trending-repos, GitHub'ın trending sayfasındaki projeleri otomatik olarak takip eden, günlük olarak güncellenen bir liste. Proje her gün gece yarısı UTC'de çalışıyor ve trending reposu analiz edip sonuçları README.md dosyasına yazıyor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temel özellikler:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔄 Günlük otomatik güncellemeler&lt;/li&gt;
&lt;li&gt;📊 Geçmiş karşılaştırmaları ve sıralama değişiklikleri&lt;/li&gt;
&lt;li&gt;📈 ASCII grafikleri ve trend görselleştirmeleri&lt;/li&gt;
&lt;li&gt;🏆 En hızlı büyüyen repolar (rising stars)&lt;/li&gt;
&lt;li&gt;💾 7 günlük geçmiş veri saklama&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Nasıl Çalışır?
&lt;/h2&gt;

&lt;p&gt;Proje, GitHub Actions kullanarak otomatik olarak çalışıyor. Her gün gece yarısı (UTC) bir workflow tetikleniyor, GitHub trending sayfasını scrape ediyor, verileri analiz ediyor ve sonuçları README.md dosyasına yazıyor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Veri toplama süreci:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GitHub trending sayfasını scrape etme (Cheerio ile)&lt;/li&gt;
&lt;li&gt;GitHub Search API'den ek veri alma (fallback olarak)&lt;/li&gt;
&lt;li&gt;Projeleri dil kategorilerine göre ayırma&lt;/li&gt;
&lt;li&gt;Geçmiş verilerle karşılaştırma yapma&lt;/li&gt;
&lt;li&gt;README.md'yi otomatik güncelleme&lt;/li&gt;
&lt;/ol&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%2Frjvid897tnn6ob4yg8i9.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%2Frjvid897tnn6ob4yg8i9.png" alt="GitHub Actions" width="800" height="367"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;CI/CD pipeline ile otomatik workflow yönetimi&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Özellikler
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Günlük Otomasyon
&lt;/h3&gt;

&lt;p&gt;GitHub Actions ile her gün otomatik olarak çalışıyor. Manuel hiçbir işlem gerektirmiyor. Sistem her gün gece yarısı UTC'de trending verilerini çekip README.md'yi güncelliyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Geçmiş Takibi
&lt;/h3&gt;

&lt;p&gt;Proje, son 7 günün verilerini saklıyor. Bu sayede bir projenin trending listesindeki konumu nasıl değişmiş görebiliyorsunuz. Yeni giren projeler, yükselenler ve düşenler hakkında detaylı bilgi veriliyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dil Bazlı Sıralama
&lt;/h3&gt;

&lt;p&gt;Trending projeleri programlama diline göre kategorize ediyor. JavaScript, Python, TypeScript, Go, Rust gibi popüler dillerdeki projeleri ayrı ayrı takip edebiliyorsunuz.&lt;/p&gt;

&lt;h3&gt;
  
  
  Görselleştirme
&lt;/h3&gt;

&lt;p&gt;ASCII grafikleri ile projelerin yükselişini ve düşüşünü görsel olarak takip edebiliyorsunuz. Hangi projelerin kaç yıldız aldığını, hangi hızla büyüdüklerini grafiklerden görebiliyorsunuz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teknik Detaylar
&lt;/h2&gt;

&lt;p&gt;Proje Node.js ile yazıldı ve ES Modules kullanıyor. GitHub Actions ile otomatikleştirildi ve Octokit library'i ile GitHub API'ye entegre edildi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kullanılan teknolojiler:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 20+&lt;/li&gt;
&lt;li&gt;GitHub Actions (cron tabanlı scheduling)&lt;/li&gt;
&lt;li&gt;Octokit (GitHub API client)&lt;/li&gt;
&lt;li&gt;Cheerio (web scraping)&lt;/li&gt;
&lt;li&gt;Axios (HTTP requests)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sonuç
&lt;/h2&gt;

&lt;p&gt;awesome-trending-repos projesi ile GitHub'taki trending projeleri otomatik olarak takip edebiliyorsunuz. Her gün güncellenen liste ile en yeni ve en popüler projeleri kaçırmıyorsunuz.&lt;/p&gt;

&lt;p&gt;Proje hem kişisel kullanım için hem de developer community'si için değerli bir kaynak oluşturuyor. Otomasyon sayesinde zaman kazandırıyor ve trendleri takip etmeyi kolaylaştırıyor.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu yazı &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt; aracılığıyla DEV.to'ya gönderilmiştir.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>automation</category>
      <category>devops</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Whop-MCP: The AI Revolution in Store Management and the Signalyze VIP Story</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Thu, 05 Mar 2026 18:21:36 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/whop-mcp-the-ai-revolution-in-store-management-and-the-signalyze-vip-story-2ede</link>
      <guid>https://dev.to/furkankoykiran/whop-mcp-the-ai-revolution-in-store-management-and-the-signalyze-vip-story-2ede</guid>
      <description>&lt;p&gt;Imagine you have a digital product. It could be a Telegram signal group, a SaaS application, or even a high-value Excel sheet... When you decide to sell it to the world, the biggest hurdle isn't usually writing the code—it's the &lt;strong&gt;operations&lt;/strong&gt;. Payments, memberships, invoices, customer reviews... before you know it, you're doing more "shopkeeping" than actual developing.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Whop.com&lt;/strong&gt; shines. Whop is like "Shopify on Steroids" for digital creators. But today, our main topic isn't just Whop itself, but how we made it "smarter."&lt;/p&gt;

&lt;p&gt;Today, I’ll share how we handed over the "keys" of your Whop store to AI assistants (Claude, Cursor, or Gemini), the technical storms we weathered, and how we autonomously built and optimized the &lt;strong&gt;Signalyze VIP&lt;/strong&gt; store.&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%2F611s45p71aiatflngb2i.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%2F611s45p71aiatflngb2i.png" alt="Whop Logo" width="400" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Whop: The new fortress of the digital economy.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What is Whop? (A Friendly Overview)
&lt;/h2&gt;

&lt;p&gt;If you haven't heard of Whop, let me summarize: In the past, to sell something digital, you had to set up a POS, build a membership system, write Discord bots, and handle a mountain of tasks. Whop centralizes all of this under a single, powerful "Dashboard."&lt;/p&gt;

&lt;p&gt;Picture waking up with a brilliant trading strategy you want to share with the world. Whop gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instant Start:&lt;/strong&gt; Create an "Access Pass" in seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Payments:&lt;/strong&gt; Accept payments worldwide (including crypto!).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Management:&lt;/strong&gt; Deliver content via Discord, Telegram, or a dedicated web portal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Insights:&lt;/strong&gt; Track who bought what, when they cancelled, and which region is most profitable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, Whop is the sanctuary for those who want to focus on their craft while someone else handles the selling. But every successful sanctuary has a cost: &lt;strong&gt;Management overhead.&lt;/strong&gt; As products and campaigns grow, you can get lost in the dashboard. That’s where AI comes to the rescue.&lt;/p&gt;


&lt;h2&gt;
  
  
  Enter MCP: The Magic Bridge
&lt;/h2&gt;

&lt;p&gt;In my previous posts (e.g., DevTo-MCP, OmniWire-MCP), I discussed the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;. MCP is the magic bridge between AI models and the outside world.&lt;/p&gt;

&lt;p&gt;In the modern era, AI assistants like Claude are incredibly smart but essentially "blind and deaf." They can only talk about their training data. We need to give them a window to the real world. Think of MCP as a &lt;strong&gt;"USB Drive"&lt;/strong&gt; or a &lt;strong&gt;"Universal Adapter"&lt;/strong&gt; for AI models.&lt;/p&gt;
&lt;h3&gt;
  
  
  What are the Benefits of Adding MCP to Whop?
&lt;/h3&gt;

&lt;p&gt;How does it make life easier for the average store owner? Let’s look at real scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instant Analysis:&lt;/strong&gt; Ask Claude, "Analyze which package performed best last week."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation:&lt;/strong&gt; Tell Cursor, "Create a new promo code and announce it to all VIP members."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content SEO:&lt;/strong&gt; Have your AI assistant fill in empty product descriptions with SEO-optimized copy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We did exactly that. With the &lt;strong&gt;Whop-MCP&lt;/strong&gt; server, we turned Whop's massive API ecosystem into a set of "Tools" that AI can understand. Now, AI doesn't just write code; it reads your business data and takes action on your behalf.&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%2Frpqbb0rt17eqjxdtjlpy.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%2Frpqbb0rt17eqjxdtjlpy.png" alt="MCP Architecture" width="800" height="379"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The bridge between AI and Whop: Model Context Protocol.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Technical Deep Dive: Why TypeScript and Whop API v2?
&lt;/h2&gt;

&lt;p&gt;When it comes to software, we couldn't leave anything to chance. An AI managing your financial data has zero room for error. That’s why &lt;strong&gt;TypeScript&lt;/strong&gt; and strong typing were non-negotiable.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Racing with the V2 API: Detailed Analysis
&lt;/h3&gt;

&lt;p&gt;Whop's API is currently in version 2 and is highly dynamic. While it's faster and more comprehensive than V1, it holds some "surprises" for developers. Some critical differences we noted during development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Consistency:&lt;/strong&gt; Some endpoints return an &lt;code&gt;empty list&lt;/code&gt; instead of &lt;code&gt;null&lt;/code&gt; when no data exists. The AI must handle this correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price Data:&lt;/strong&gt; Prices that were numbers in V1 sometimes arrive as strings in V2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expansion Logic:&lt;/strong&gt; When requesting related plans, the API might only return a list of IDs.
We overcame these hurdles using &lt;strong&gt;Zod&lt;/strong&gt; schemas to validate every step. Every piece of data entering our code passed through a Zod "customs check."&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. The "Invalid Date" Nightmare (safeDate fix)
&lt;/h3&gt;

&lt;p&gt;One of the most frustrating errors we encountered was date formatting in JSON data. Whop sometimes returns Unix Timestamps (seconds), sometimes Milliseconds, and sometimes null. If an AI assistant puts this into &lt;code&gt;new Date()&lt;/code&gt;, the whole system crashes with an "Invalid time value" error.&lt;/p&gt;

&lt;p&gt;To solve this, we placed a &lt;code&gt;safeDate&lt;/code&gt; utility function at the heart of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;safeDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2000000000&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&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;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This small but vital piece of code kept our project 100% stable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Case Study: Signalyze VIP Optimization
&lt;/h2&gt;

&lt;p&gt;We tested this in the real world with the &lt;strong&gt;Signalyze VIP&lt;/strong&gt; store.&lt;/p&gt;

&lt;p&gt;Initially, product names were basic and descriptions lacked SEO. We put Whop-MCP in the driver's seat:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scan all products.&lt;/li&gt;
&lt;li&gt;Synchronize with the corporate site (signalyze.arcehub.com).&lt;/li&gt;
&lt;li&gt;Update descriptions emphasizing character personas like &lt;strong&gt;Guardian (Risk Expert)&lt;/strong&gt;, &lt;strong&gt;Maverick (Opportunity Hunter)&lt;/strong&gt;, and &lt;strong&gt;Arbiter (Wisdom Master)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The transformation was instant. All done autonomously via AI tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Open Source?
&lt;/h2&gt;

&lt;p&gt;We believe in &lt;strong&gt;Trust&lt;/strong&gt;, &lt;strong&gt;Community Strength&lt;/strong&gt;, and building a robust &lt;strong&gt;Ecosystem&lt;/strong&gt;. Transparency is everything when it comes to tools managing your business.&lt;/p&gt;

&lt;p&gt;We are faster together. Every star on our GitHub repo is a signature on the AI revolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/furkankoykiran/whop-mcp" rel="noopener noreferrer"&gt;👉 GitHub: furkankoykiran/whop-mcp&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Announcement:&lt;/strong&gt; This entire post, its images, and the multi-platform publishing process (including GitHub operations and Dev.to distribution) were autonomously managed by an AI assistant leveraging both the &lt;strong&gt;Whop-MCP&lt;/strong&gt; and &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt; servers. There's nothing more exciting than an assistant telling its own birth story!&lt;/p&gt;

&lt;p&gt;Stay with the code and the context.&lt;/p&gt;

</description>
      <category>whop</category>
      <category>mcp</category>
      <category>typescript</category>
      <category>automation</category>
    </item>
    <item>
      <title>Whop-MCP: Mağaza Yönetiminde Yapay Zeka Devrimi ve Signalyze VIP Hikayesi</title>
      <dc:creator>Furkan Köykıran</dc:creator>
      <pubDate>Thu, 05 Mar 2026 18:16:03 +0000</pubDate>
      <link>https://dev.to/furkankoykiran/whop-mcp-magaza-yonetiminde-yapay-zeka-devrimi-ve-signalyze-vip-hikayesi-g06</link>
      <guid>https://dev.to/furkankoykiran/whop-mcp-magaza-yonetiminde-yapay-zeka-devrimi-ve-signalyze-vip-hikayesi-g06</guid>
      <description>&lt;p&gt;Dijital bir ürününüz olduğunu hayal edin. Belki bir Telegram sinyal grubu, belki bir SaaS uygulaması, belki de sadece çok değerli bir Excel tablosu... Bunu dünyaya satmak istediğinizde karşınıza çıkan en büyük engel genelde kod yazmak değil, &lt;strong&gt;operasyon&lt;/strong&gt; olur. Ödemeler, üyelikler, faturalar, müşteri yorumları derken bir bakmışsınız kod yazmaktan çok "mağazacılık" yapıyorsunuz.&lt;/p&gt;

&lt;p&gt;İşte tam bu noktada devreye &lt;strong&gt;Whop.com&lt;/strong&gt; giriyor. Whop, dijital içerik üreticileri için adeta bir "Shopify on Steroids" gibi. Ama bugün asıl konumuz Whop'un kendisi değil, onu nasıl "akıllandırdığımız".&lt;/p&gt;

&lt;p&gt;Bugün size, AI asistanlarımıza (Claude, Cursor veya Gemini) Whop mağazanızın "anahtarını" nasıl teslim ettiğimizi, karşılaştığımız teknik fırtınaları ve &lt;strong&gt;Signalyze VIP&lt;/strong&gt; mağazasını otonom olarak nasıl ayağa kaldırdığımızı anlatacağım.&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%2F611s45p71aiatflngb2i.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%2F611s45p71aiatflngb2i.png" alt="Whop Logo" width="400" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Whop: Dijital ekonominin yeni kalesi.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Whop Nedir? (Samimi Bir Bakış)
&lt;/h2&gt;

&lt;p&gt;Whop'u hiç duymadıysanız şöyle özetleyeyim: Eskiden bir şey satmak için pos cihazı bağla, üyelik sistemi kur, Discord botu yaz gibi tonla işle uğraşırdınız. Whop, bunların hepsini tek bir "Dashboard" altında topluyor. &lt;/p&gt;

&lt;p&gt;Düşünün ki bir sabah uyandınız ve harika bir ticaret stratejiniz var. Bunu insanlara satmak istiyorsunuz. Whop size şu imkanları sunar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hızlı Başlangıç:&lt;/strong&gt; Saniyeler içinde bir "Access Pass" oluşturabiliyorsunuz.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Ödeme:&lt;/strong&gt; Ödemeleri dünya çapında (kripto dahil!) kabul edebiliyorsunuz.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Topluluk Yönetimi:&lt;/strong&gt; Üyelerinize Discord, Telegram veya özel bir web sayfası üzerinden içerik sunabiliyorsunuz.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Güçlü Dashboard:&lt;/strong&gt; Kim ne almış, ne zaman iptal etmiş, en çok hangi bölgeniz kar getirmiş; hepsini görebiliyorsunuz.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  İşte MCP Burada Devreye Giriyor!
&lt;/h2&gt;

&lt;p&gt;Modern devirde AI asistanları (Claude gibi) çok akıllı ama dış dünyadan kopuklar. &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; standartı, bu asistanlara dış dünyaya açılan birer pencere verir. Whop-MCP ile Whop'un devasa API ekosistemini AI'ın anlayabileceği birer "Tool" haline getirdik.&lt;/p&gt;


&lt;h2&gt;
  
  
  Teknik Derinlik: Neden TypeScript?
&lt;/h2&gt;

&lt;p&gt;Finansal veriler hata kabul etmez. &lt;strong&gt;TypeScript&lt;/strong&gt; ve &lt;strong&gt;Zod&lt;/strong&gt; ile her adımı doğruladık.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. "Invalid Date" Kabusu (safeDate fix)
&lt;/h3&gt;

&lt;p&gt;Whop API'sinden gelen tutarsız tarih formatlarını yönetmek için &lt;code&gt;safeDate&lt;/code&gt; utility fonksiyonunu geliştirdik:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;safeDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2000000000&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&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;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu küçük kod parçası, sistemin %100 stabil kalmasını sağladı.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gerçek Bir Case Study: Signalyze VIP Optimizasyonu
&lt;/h2&gt;

&lt;p&gt;Signalyze VIP mağazasını Whop-MCP ile baştan aşağı yeniledik. AI asistanına mağazadaki eksikleri belirlemesini ve ürün açıklamalarını &lt;strong&gt;Guardian&lt;/strong&gt;, &lt;strong&gt;Maverick&lt;/strong&gt; ve &lt;strong&gt;Arbiter&lt;/strong&gt; karakterlerine uygun, SEO uyumlu İngilizce metinlerle güncellemesini söyledik.&lt;/p&gt;

&lt;p&gt;Sonuç? Hiçbir browser penceresi açmadan, saniyeler içinde profesyonel bir mağaza dönüşümü.&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%2F7v5ozrbtzqajcbe02hr6.webp" 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%2F7v5ozrbtzqajcbe02hr6.webp" alt="MCP Concept" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Neden Açık Kaynak?
&lt;/h2&gt;

&lt;p&gt;Transparanlık, güven ve topluluk gücü için projemiz açık kaynak:&lt;br&gt;
&lt;a href="https://github.com/furkankoykiran/whop-mcp" rel="noopener noreferrer"&gt;👉 GitHub: furkankoykiran/whop-mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Birlikte daha hızlıyız.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Önemli Duyuru:&lt;/strong&gt; Bu blog yazısının içeriği, görselleri ve tüm yayınlama süreci (GitHub operasyonları ve Dev.to dağıtımı), &lt;strong&gt;Whop-MCP&lt;/strong&gt; ve &lt;a href="https://github.com/furkankoykiran/DevTo-MCP" rel="noopener noreferrer"&gt;DevTo-MCP&lt;/a&gt; sunucuları kullanılarak bir AI asistanı tarafından otonom olarak gerçekleştirilmiştir. Bir asistanın kendi doğum hikayesini anlatması kadar heyecan verici bir şey yok!&lt;/p&gt;

&lt;p&gt;Kodla ve bağlamla kalın.&lt;/p&gt;

</description>
      <category>whop</category>
      <category>mcp</category>
      <category>typescript</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
