<?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: Yash</title>
    <description>The latest articles on DEV Community by Yash (@yashbogam).</description>
    <link>https://dev.to/yashbogam</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3227105%2Fce4405aa-a05e-463b-8060-3bc1b88987f9.png</url>
      <title>DEV Community: Yash</title>
      <link>https://dev.to/yashbogam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yashbogam"/>
    <language>en</language>
    <item>
      <title>Debugging AI agents by replaying the exact run, not the logs</title>
      <dc:creator>Yash</dc:creator>
      <pubDate>Wed, 08 Jul 2026 20:10:17 +0000</pubDate>
      <link>https://dev.to/yashbogam/debugging-ai-agents-by-replaying-the-exact-run-not-the-logs-1fd4</link>
      <guid>https://dev.to/yashbogam/debugging-ai-agents-by-replaying-the-exact-run-not-the-logs-1fd4</guid>
      <description>&lt;p&gt;The hardest part of building with LLM agents isn't writing the agent. It's the Tuesday afternoon when one misbehaves in production and you have to work out why. The run was non-deterministic, so you can't just re-run it. The logs are spread across your app, your model provider, and your vector DB. And the inputs that actually produced the bad output are already gone.&lt;/p&gt;

&lt;p&gt;I hit this loop enough times that I built a tool for it. &lt;a href="https://retraceai.tech" rel="noopener noreferrer"&gt;Retrace&lt;/a&gt; records an agent run, lets you replay it step by step like a video, and lets you fork from the step that broke to test a fix — re-running only the part that changed. This post is a walk through the workflow, the design decisions behind it, and where it's still rough. It's open source (MIT) and I built it solo, so the "still rough" section is honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are agents so hard to debug?
&lt;/h2&gt;

&lt;p&gt;A stack trace tells you the line that threw. An agent failure is rarely that tidy. The real cause is usually one of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a tool call three steps back that returned junk,&lt;/li&gt;
&lt;li&gt;a prompt that slowly drifted off-task across turns,&lt;/li&gt;
&lt;li&gt;a retrieval that pulled the wrong context,&lt;/li&gt;
&lt;li&gt;or a model call that was fine in isolation but wrong given the state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the time the bad answer surfaces, the chain that produced it is buried. Print statements don't help either, because the next run takes a different path. You need the actual run preserved, not a summary of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you record a run without rewriting your agent?
&lt;/h2&gt;

&lt;p&gt;You wrap your agent once. In Python it's a decorator; in TypeScript it's a wrapper. After that, every model call, tool call, and error is captured automatically as a span on a trace. Calls to OpenAI, Anthropic, and Gemini are instrumented for you, so there's no manual logging to maintain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fra3fxcwj6dc44lhqbgrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fra3fxcwj6dc44lhqbgrx.png" alt="Retrace: one decorator records the whole agent run — every model call, tool call and error as spans — and the CLI forks a failed step" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The capture path is built to not lose data and to not get in your way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an offline buffer queues events and flushes on reconnect,&lt;/li&gt;
&lt;li&gt;transport falls back WebSocket → HTTP → OpenTelemetry if the socket drops,&lt;/li&gt;
&lt;li&gt;PII (emails, keys, tokens) is redacted before anything is stored,&lt;/li&gt;
&lt;li&gt;a sample rate keeps high-volume agents affordable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once recorded, the run becomes an interactive timeline you can play, pause, and scrub. That alone changed how I debug: I stopped guessing from logs and started watching where the run actually went wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does forking actually work?
&lt;/h2&gt;

&lt;p&gt;This is the part I use most. You pick the step that went wrong, change its input, and Retrace re-executes the agent from that point forward. Everything before the fork replays from the recording, so it costs almost nothing. Only the part that genuinely diverges makes real model calls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0cq6vzz727jcn94eoac5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0cq6vzz727jcn94eoac5.png" alt="Fork and cascade replay: pre-fork spans replay from the recorded tape at near-zero cost, post-fork spans re-execute live, then the two runs are diffed" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you get a side-by-side diff of the original run versus the fork, down to the first step where they differ. So instead of "I think this prompt change helped," you get a concrete before/after on the exact run that failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you prove a fix worked before shipping?
&lt;/h2&gt;

&lt;p&gt;Forking gets you a comparison; proving is the next step. You can re-run a proposed change against the failed run and get a verdict: improved, regressed, unchanged, or inconclusive. There's a bisect that binary-searches the run to find the exact step whose change flips the result, and a way to apply one fix across many failed runs at once to check it holds beyond a single example.&lt;/p&gt;

&lt;p&gt;If you want this in CI, there's an eval gate: score a run with an LLM judge against your own criteria, and the gate exits non-zero below your threshold, so a regression fails the build instead of reaching users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp8cv43werj6hqz9n1evz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp8cv43werj6hqz9n1evz.png" alt="Prove the fix: replay your change against the failed run, diff the first divergence, get an improved, regressed or unchanged verdict, and gate CI on the score" width="800" height="432"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="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;Eval Gate&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;retrace eval gate --evaluation $EVAL_ID --trace $TRACE_ID --threshold &lt;/span&gt;&lt;span class="m"&gt;0.8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What's under the hood?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python and TypeScript SDKs, published to PyPI and npm.&lt;/li&gt;
&lt;li&gt;A Fastify + PostgreSQL backend, with pgvector for semantic search over past runs (find a span or a past failure by meaning, not just by id).&lt;/li&gt;
&lt;li&gt;Buffered ingestion with backpressure, so a burst of traffic degrades gracefully instead of overloading the datastore.&lt;/li&gt;
&lt;li&gt;OpenTelemetry ingest, so you can push spans from any language even without the SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where it's still rough (the honest part)&lt;/p&gt;

&lt;p&gt;I built this solo with an AI-assisted workflow, and it's early. Replay re-calls models live, so some divergence reflects provider non-determinism rather than a real regression — you treat diffs as signals to inspect, not gospel. The docs have gaps. And I haven't stress-tested every framework people use.&lt;/p&gt;

&lt;p&gt;That's exactly why I'm posting. If you run agents in production: what part of debugging a bad run wastes the most of your time today — reproducing it, finding the root cause, or proving the fix? I want to build against real workflows, not my assumptions. If you try it and it breaks, telling me where is the single most useful thing right now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.retraceai.tech" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Retraceai-tech" rel="noopener noreferrer"&gt;
        Retraceai-tech
      &lt;/a&gt; / &lt;a href="https://github.com/Retraceai-tech/retrace-sdk" rel="noopener noreferrer"&gt;
        retrace-sdk
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Python &amp;amp; TypeScript SDKs for Retrace — the execution replay engine for AI agents.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/Retraceai-tech/retrace-sdk/assets/banner.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FRetraceai-tech%2Fretrace-sdk%2FHEAD%2Fassets%2Fbanner.gif" alt="Retrace" width="480"&gt;&lt;/a&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/3eb7efb30158d13c568ff5b3760336477b8ee3e46b7ba0ff77ef1a20bda5bb22/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d3337373641423f6c6f676f3d707974686f6e266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/3eb7efb30158d13c568ff5b3760336477b8ee3e46b7ba0ff77ef1a20bda5bb22/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d3337373641423f6c6f676f3d707974686f6e266c6f676f436f6c6f723d7768697465" alt="Python"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/d2b19c56bf530067483d8d2756fac7800e0aef54ef4360460d778c23ccc3db2b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547970655363726970742d3331373843363f6c6f676f3d74797065736372697074266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/d2b19c56bf530067483d8d2756fac7800e0aef54ef4360460d778c23ccc3db2b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547970655363726970742d3331373843363f6c6f676f3d74797065736372697074266c6f676f436f6c6f723d7768697465" alt="TypeScript"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Record every LLM call, tool invocation, and error your agent makes. Replay it step-by-step like a video. Fork from any point, change the input, and watch the whole agent re-execute down a new path. Share any run as an interactive, public link.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/Retraceai-tech/retrace-sdk#python" rel="noopener noreferrer"&gt;Python&lt;/a&gt; · &lt;a href="https://github.com/Retraceai-tech/retrace-sdk#typescript" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; · &lt;a href="https://github.com/Retraceai-tech/retrace-sdk#how-it-works" rel="noopener noreferrer"&gt;How It Works&lt;/a&gt; · &lt;a href="https://docs.retraceai.tech" rel="nofollow noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Python&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install retrace-sdk&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-python notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;retrace&lt;/span&gt;

&lt;span class="pl-s1"&gt;retrace&lt;/span&gt;.&lt;span class="pl-c1"&gt;configure&lt;/span&gt;(&lt;span class="pl-s1"&gt;api_key&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;"rt_..."&lt;/span&gt;)

&lt;span class="pl-en"&gt;@&lt;span class="pl-s1"&gt;retrace&lt;/span&gt;.&lt;span class="pl-c1"&gt;record&lt;/span&gt;(&lt;span class="pl-s1"&gt;name&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;"research-agent"&lt;/span&gt;, &lt;span class="pl-s1"&gt;resumable&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;)&lt;/span&gt;
&lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;run_agent&lt;/span&gt;(&lt;span class="pl-s1"&gt;prompt&lt;/span&gt;: &lt;span class="pl-smi"&gt;str&lt;/span&gt;):
    &lt;span class="pl-s1"&gt;plan&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;call_planner&lt;/span&gt;(&lt;span class="pl-s1"&gt;prompt&lt;/span&gt;)    &lt;span class="pl-c"&gt;# captured automatically&lt;/span&gt;
    &lt;span class="pl-s1"&gt;results&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;call_tools&lt;/span&gt;(&lt;span class="pl-s1"&gt;plan&lt;/span&gt;)     &lt;span class="pl-c"&gt;# captured automatically&lt;/span&gt;
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-en"&gt;summarize&lt;/span&gt;(&lt;span class="pl-s1"&gt;results&lt;/span&gt;)      &lt;span class="pl-c"&gt;# captured automatically&lt;/span&gt;

&lt;span class="pl-en"&gt;run_agent&lt;/span&gt;(&lt;span class="pl-s"&gt;"What changed in vector databases this year?"&lt;/span&gt;)&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;See &lt;a href="https://github.com/Retraceai-tech/retrace-sdk/python/README.md" rel="noopener noreferrer"&gt;&lt;code&gt;python/README.md&lt;/code&gt;&lt;/a&gt; for the full reference.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;TypeScript&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install retrace-sdk&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;configure&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;trace&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"retrace-sdk"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-en"&gt;configure&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;apiKey&lt;/span&gt;: &lt;span class="pl-s"&gt;"rt_..."&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Retraceai-tech/retrace-sdk" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
      <category>ai</category>
      <category>python</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built Retrace: replay and fork your AI agent runs like a video</title>
      <dc:creator>Yash</dc:creator>
      <pubDate>Tue, 07 Jul 2026 21:22:54 +0000</pubDate>
      <link>https://dev.to/yashbogam/i-built-retrace-replay-and-fork-your-ai-agent-runs-like-a-video-636</link>
      <guid>https://dev.to/yashbogam/i-built-retrace-replay-and-fork-your-ai-agent-runs-like-a-video-636</guid>
      <description>&lt;p&gt;If you've built anything with LLM agents, you know the annoying part isn't writing the agent — it's figuring out what went wrong when it misbehaves. The run is non-deterministic, the logs are scattered, and reproducing the exact failure is a pain.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://retraceai.tech" rel="noopener noreferrer"&gt;Retrace&lt;/a&gt; to make that loop less miserable: record a run, replay it step by step, and fork from any step to test a fix.&lt;/p&gt;

&lt;p&gt;How it works&lt;/p&gt;

&lt;p&gt;You wrap your agent function once — a decorator in Python or a wrapper in TypeScript. After that, every LLM call, tool call, and error is captured automatically as a span inside a trace. Calls to OpenAI, Anthropic, and Gemini get picked up without extra instrumentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fta6e729ncvusc6yye7qc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fta6e729ncvusc6yye7qc.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replay — the run shows up as an interactive timeline you can play and scrub through, so you can see exactly where it broke instead of guessing from logs.&lt;/li&gt;
&lt;li&gt;Fork — pick the step that went wrong, change the input, and Retrace re-executes the agent from that point forward. Everything before the fork replays from the recording, so you're not paying to re-run the whole thing, and you get a side-by-side diff of the original vs. the new path.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The stack&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python + TypeScript SDKs (published to PyPI and npm)&lt;/li&gt;
&lt;li&gt;Fastify + PostgreSQL, with pgvector for semantic search over past runs&lt;/li&gt;
&lt;li&gt;Buffered ingestion over WebSocket with HTTP and OpenTelemetry fallbacks, so a run isn't lost if the socket drops&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0wsydc7y0is442qns175.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0wsydc7y0is442qns175.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Honest context&lt;/p&gt;

&lt;p&gt;I built this solo, It's still early — I'd genuinely like feedback from people who run agents in production about what's useful and what's missing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.retraceai.tech" rel="noopener noreferrer"&gt;docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it, tell me where it breaks. That's the most useful thing right now.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
