<?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: Venkata Rahul Murarisetty</title>
    <description>The latest articles on DEV Community by Venkata Rahul Murarisetty (@venkatarahul27).</description>
    <link>https://dev.to/venkatarahul27</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%2F4026429%2F393592ad-af50-40f5-8d22-11b763fce0a4.jpg</url>
      <title>DEV Community: Venkata Rahul Murarisetty</title>
      <link>https://dev.to/venkatarahul27</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/venkatarahul27"/>
    <language>en</language>
    <item>
      <title>Focus Three: a distributed to-do prioritizer built with ADK, A2A and Cloud Run</title>
      <dc:creator>Venkata Rahul Murarisetty</dc:creator>
      <pubDate>Sat, 01 Aug 2026 23:03:54 +0000</pubDate>
      <link>https://dev.to/venkatarahul27/focus-three-a-distributed-to-do-prioritizer-built-with-adk-a2a-and-cloud-run-l59</link>
      <guid>https://dev.to/venkatarahul27/focus-three-a-distributed-to-do-prioritizer-built-with-adk-a2a-and-cloud-run-l59</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is my submission for &lt;a href="https://dev.to/deved/build-multi-agent-systems"&gt;DEV Education Track: Build Multi-Agent Systems with ADK&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Focus Three takes a messy free-text brain dump and gives back the three things you should actually do today, with the reasoning attached. By messy I mean the usual: items are vague, deadlines are implied rather than stated, and half the entries are really three tasks in a trenchcoat.&lt;/p&gt;

&lt;p&gt;Ranking is not the hard part. The hard part is that one prompt asked to prioritize a list will skip items it does not understand, quietly merge two tasks into one, and still hand back a confident top three that leaves out the thing that was on fire. None of that shows up in the output. Splitting the job across specialists made each failure surface somewhere I could fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Run Embed
&lt;/h2&gt;


&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://focus-three-33ffpbl4ya-uc.a.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;


&lt;p&gt;Paste in your own brain dump and watch it run. The frontend streams progress events, so you can see each specialist report in before the final three appear.&lt;/p&gt;

&lt;p&gt;Give it a minute on the first run. The services scale to zero, so a cold start wakes five containers before the first agent speaks; after that a run takes about a minute.&lt;/p&gt;

&lt;p&gt;All six services carry the DEV label from the embed guide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud run deploy focus-three &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--source&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-central1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--allow-unauthenticated&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--labels&lt;/span&gt; dev-tutorial&lt;span class="o"&gt;=&lt;/span&gt;blog-devcommunity2026
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Your Agents
&lt;/h2&gt;

&lt;p&gt;Four LLM agents, all running &lt;code&gt;gemini-3-flash-preview&lt;/code&gt;, each with one job, plus a small Python step that drives the retry loop.&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%2Fmermaid.ink%2Fimg%2FJSV7aW5pdDogeydmbG93Y2hhcnQnOiB7J25vZGVTcGFjaW5nJzogMjgsICdyYW5rU3BhY2luZyc6IDI4LCAncGFkZGluZyc6IDZ9LCAndGhlbWVWYXJpYWJsZXMnOiB7J2ZvbnRTaXplJzogJzE4cHgnfX19JSUKZmxvd2NoYXJ0IFRECklOKFsiYnJhaW4gZHVtcCJdKTo6OmlvIC0tPiBGRQpGRVsiPGI-RnJvbnRlbmQ8L2I-PGJyLz5DbG91ZCBSdW4gc2VydmljZSAxIl06OjppbmZyYQpzdWJncmFwaCBPUkNIWyJPcmNoZXN0cmF0b3IgwrcgU2VxdWVudGlhbEFnZW50IMK3IENsb3VkIFJ1biBzZXJ2aWNlIDIiXQpkaXJlY3Rpb24gVEIKc3ViZ3JhcGggTE9PUFsic3RlcCAxIMK3IHBhcnNlIGxvb3AgwrcgTG9vcEFnZW50LCBtYXggMyBwYXNzZXMiXQpkaXJlY3Rpb24gTFIKVEFbIjxiPlRhc2sgQW5hbHl6ZXI8L2I-PGJyLz5BMkEg4oaSIHNlcnZpY2UgMzxici8-c3BsaXRzIHRoZSBkdW1wIGludG88YnIvPmF0b21pYyB0YXNrcyJdOjo6YWdlbnQKQ1ZbIjxiPkNvdmVyYWdlIFZhbGlkYXRvcjwvYj48YnIvPkEyQSDihpIgc2VydmljZSA0PGJyLz5zdHJpY3QgcGFzcyAvIGZhaWwgKyBmZWVkYmFjayJdOjo6YWdlbnQKRVNDe3siPGI-ZXNjYWxhdGlvbiBjaGVjazwvYj48YnIvPmluLXByb2Nlc3MgUHl0aG9uIn19Ojo6Y29kZQpUQSAtLT4gQ1YgLS0-IEVTQwpFU0MgLS4tPnwiZmFpbDogcmV0cnkgd2l0aCBmZWVkYmFjayJ8IFRBCmVuZApzdWJncmFwaCBTVEVQU1siICJdCmRpcmVjdGlvbiBMUgpVQ1siPGI-c3RlcCAyIMK3IFVyZ2VuY3kgQ2hlY2tlcjwvYj48YnIvPkEyQSDihpIgc2VydmljZSA1PGJyLz5zY29yZXMgZXZlcnkgdGFzayAwLTEwMCJdOjo6YWdlbnQKRkFbIjxiPnN0ZXAgMyDCtyBGb2N1cyBBZ2VudDwvYj48YnIvPkEyQSDihpIgc2VydmljZSA2PGJyLz5waWNrcyB0aHJlZSwgc2hhcGVzIHRoZSBkYXkiXTo6OmFnZW50ClVDID09PiBGQQplbmQKRVNDID09PnwicGFzczogZXNjYWxhdGU9VHJ1ZSJ8IFVDCmVuZApGRSA9PT58IkhUVFAgwrcgcHJvZ3Jlc3MgZXZlbnRzInwgVEEKRkEgLS0-IE9VVChbInRocmVlIHRhc2tzLCB3aXRoIHJlYXNvbnM8YnIvPmFuZCB3aGF0IHdhcyBsZWZ0IG91dCJdKTo6OmlvCmNsYXNzRGVmIGlvIGZpbGw6I2ZlZjNjNyxzdHJva2U6I2Y1OWUwYixzdHJva2Utd2lkdGg6M3B4LGNvbG9yOiM3ODM1MGYKY2xhc3NEZWYgaW5mcmEgZmlsbDojZGJlYWZlLHN0cm9rZTojMjU2M2ViLHN0cm9rZS13aWR0aDozcHgsY29sb3I6IzFlM2E4YQpjbGFzc0RlZiBhZ2VudCBmaWxsOiNkY2ZjZTcsc3Ryb2tlOiMxNmEzNGEsc3Ryb2tlLXdpZHRoOjNweCxjb2xvcjojMTQ1MzJkCmNsYXNzRGVmIGNvZGUgZmlsbDojZjNlOGZmLHN0cm9rZTojOTMzM2VhLHN0cm9rZS13aWR0aDozcHgsY29sb3I6IzU4MWM4NwpzdHlsZSBPUkNIIGZpbGw6I2YxZjVmOSxzdHJva2U6IzQ3NTU2OSxzdHJva2Utd2lkdGg6M3B4LGNvbG9yOiMwZjE3MmEKc3R5bGUgTE9PUCBmaWxsOiNmZmY3ZWQsc3Ryb2tlOiNlYTU4MGMsc3Ryb2tlLXdpZHRoOjNweCxzdHJva2UtZGFzaGFycmF5OiA4IDUsY29sb3I6IzdjMmQxMgpzdHlsZSBTVEVQUyBmaWxsOm5vbmUsc3Ryb2tlOm5vbmU" 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%2Fmermaid.ink%2Fimg%2FJSV7aW5pdDogeydmbG93Y2hhcnQnOiB7J25vZGVTcGFjaW5nJzogMjgsICdyYW5rU3BhY2luZyc6IDI4LCAncGFkZGluZyc6IDZ9LCAndGhlbWVWYXJpYWJsZXMnOiB7J2ZvbnRTaXplJzogJzE4cHgnfX19JSUKZmxvd2NoYXJ0IFRECklOKFsiYnJhaW4gZHVtcCJdKTo6OmlvIC0tPiBGRQpGRVsiPGI-RnJvbnRlbmQ8L2I-PGJyLz5DbG91ZCBSdW4gc2VydmljZSAxIl06OjppbmZyYQpzdWJncmFwaCBPUkNIWyJPcmNoZXN0cmF0b3IgwrcgU2VxdWVudGlhbEFnZW50IMK3IENsb3VkIFJ1biBzZXJ2aWNlIDIiXQpkaXJlY3Rpb24gVEIKc3ViZ3JhcGggTE9PUFsic3RlcCAxIMK3IHBhcnNlIGxvb3AgwrcgTG9vcEFnZW50LCBtYXggMyBwYXNzZXMiXQpkaXJlY3Rpb24gTFIKVEFbIjxiPlRhc2sgQW5hbHl6ZXI8L2I-PGJyLz5BMkEg4oaSIHNlcnZpY2UgMzxici8-c3BsaXRzIHRoZSBkdW1wIGludG88YnIvPmF0b21pYyB0YXNrcyJdOjo6YWdlbnQKQ1ZbIjxiPkNvdmVyYWdlIFZhbGlkYXRvcjwvYj48YnIvPkEyQSDihpIgc2VydmljZSA0PGJyLz5zdHJpY3QgcGFzcyAvIGZhaWwgKyBmZWVkYmFjayJdOjo6YWdlbnQKRVNDe3siPGI-ZXNjYWxhdGlvbiBjaGVjazwvYj48YnIvPmluLXByb2Nlc3MgUHl0aG9uIn19Ojo6Y29kZQpUQSAtLT4gQ1YgLS0-IEVTQwpFU0MgLS4tPnwiZmFpbDogcmV0cnkgd2l0aCBmZWVkYmFjayJ8IFRBCmVuZApzdWJncmFwaCBTVEVQU1siICJdCmRpcmVjdGlvbiBMUgpVQ1siPGI-c3RlcCAyIMK3IFVyZ2VuY3kgQ2hlY2tlcjwvYj48YnIvPkEyQSDihpIgc2VydmljZSA1PGJyLz5zY29yZXMgZXZlcnkgdGFzayAwLTEwMCJdOjo6YWdlbnQKRkFbIjxiPnN0ZXAgMyDCtyBGb2N1cyBBZ2VudDwvYj48YnIvPkEyQSDihpIgc2VydmljZSA2PGJyLz5waWNrcyB0aHJlZSwgc2hhcGVzIHRoZSBkYXkiXTo6OmFnZW50ClVDID09PiBGQQplbmQKRVNDID09PnwicGFzczogZXNjYWxhdGU9VHJ1ZSJ8IFVDCmVuZApGRSA9PT58IkhUVFAgwrcgcHJvZ3Jlc3MgZXZlbnRzInwgVEEKRkEgLS0-IE9VVChbInRocmVlIHRhc2tzLCB3aXRoIHJlYXNvbnM8YnIvPmFuZCB3aGF0IHdhcyBsZWZ0IG91dCJdKTo6OmlvCmNsYXNzRGVmIGlvIGZpbGw6I2ZlZjNjNyxzdHJva2U6I2Y1OWUwYixzdHJva2Utd2lkdGg6M3B4LGNvbG9yOiM3ODM1MGYKY2xhc3NEZWYgaW5mcmEgZmlsbDojZGJlYWZlLHN0cm9rZTojMjU2M2ViLHN0cm9rZS13aWR0aDozcHgsY29sb3I6IzFlM2E4YQpjbGFzc0RlZiBhZ2VudCBmaWxsOiNkY2ZjZTcsc3Ryb2tlOiMxNmEzNGEsc3Ryb2tlLXdpZHRoOjNweCxjb2xvcjojMTQ1MzJkCmNsYXNzRGVmIGNvZGUgZmlsbDojZjNlOGZmLHN0cm9rZTojOTMzM2VhLHN0cm9rZS13aWR0aDozcHgsY29sb3I6IzU4MWM4NwpzdHlsZSBPUkNIIGZpbGw6I2YxZjVmOSxzdHJva2U6IzQ3NTU2OSxzdHJva2Utd2lkdGg6M3B4LGNvbG9yOiMwZjE3MmEKc3R5bGUgTE9PUCBmaWxsOiNmZmY3ZWQsc3Ryb2tlOiNlYTU4MGMsc3Ryb2tlLXdpZHRoOjNweCxzdHJva2UtZGFzaGFycmF5OiA4IDUsY29sb3I6IzdjMmQxMgpzdHlsZSBTVEVQUyBmaWxsOm5vbmUsc3Ryb2tlOm5vbmU" alt="Focus Three architecture: a brain dump goes to the frontend, the orchestrator runs a parse loop over the Task Analyzer, Coverage Validator and an in-process escalation check, then the Urgency Checker and Focus Agent return three tasks" width="881" height="827"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task Analyzer.&lt;/strong&gt; Parses the raw dump into atomic tasks. It splits compound items, estimates effort in focused minutes, and records the exact source fragment each task came from. It emits a Pydantic &lt;code&gt;TaskList&lt;/code&gt; instead of prose, so nothing downstream has to re-parse English.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coverage Validator.&lt;/strong&gt; The quality gate. It reads the original input alongside the parsed list and asks one question: is everything accounted for? Unsplit compound items, dropped fragments and tasks still too vague to act on all earn a &lt;code&gt;fail&lt;/code&gt; plus specific feedback. It returns a strict pass/fail schema and is blocked from delegating or chatting, so a verdict is the only thing it can emit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Escalation check.&lt;/strong&gt; Not an agent, just Python, running in-process inside the orchestrator. It reads the validator's verdict out of shared session state and yields an event with &lt;code&gt;escalate=True&lt;/code&gt; on a pass, which is the signal the parent loop catches to break out. On a fail it yields a plain event and the loop runs again with the feedback in context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Urgency Checker.&lt;/strong&gt; Scores each task 0-100 on deadline pressure and consequence of delay, with a one-line justification per task. I kept it separate from the final pick so scoring and selection can be debugged on their own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Focus Agent.&lt;/strong&gt; Picks the final three. Not just the top three by score: it enforces a shape on the day, so it will not hand you three four-hour tasks, and it always includes at least one quick win.&lt;/p&gt;

&lt;p&gt;The Task Analyzer, the Coverage Validator and the escalation check sit inside a &lt;code&gt;LoopAgent&lt;/code&gt; capped at three iterations. That loop, the Urgency Checker and the Focus Agent sit inside a &lt;code&gt;SequentialAgent&lt;/code&gt;. Six Cloud Run services in total: the four LLM agents, the orchestrator and the frontend, wired together over A2A with agent-card URLs passed in as environment variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;p&gt;The hard part was getting honest answers, not good ones.&lt;/p&gt;

&lt;p&gt;Separating scoring from selection is what fixed that. Once the Urgency Checker has to publish a number and a one-line justification for every task, the Focus Agent cannot quietly drop the expensive ones. It has to argue for what it left out. On the test dump it returned the login bug (120 min, urgency 95), the slides (90 min, urgency 88) and the dentist (15 min, urgency 50), then explained that replying to the twelve emails scored higher urgency than the dentist but would have pushed the day to 255 minutes against a 240-minute budget. That trade-off note is the output I trust most, and it only exists because two agents disagree in the open instead of one agent deciding in private.&lt;/p&gt;

&lt;p&gt;Constraining an agent turned out to be mostly about taking capabilities away. The Coverage Validator returns a strict pass/fail schema and is blocked from delegating or replying conversationally, so a verdict is the only thing it can produce.&lt;/p&gt;

&lt;p&gt;Stack: Google ADK + A2A + Cloud Run + Gemini 3 Flash Preview&lt;/p&gt;

</description>
      <category>agents</category>
      <category>buildmultiagents</category>
      <category>gemini</category>
      <category>adk</category>
    </item>
    <item>
      <title>I Built an AI Agent with Claude's Tool-Use Loop (Web Search, SQL, and More)</title>
      <dc:creator>Venkata Rahul Murarisetty</dc:creator>
      <pubDate>Sun, 12 Jul 2026 21:42:58 +0000</pubDate>
      <link>https://dev.to/venkatarahul27/i-built-an-ai-agent-with-claudes-tool-use-loop-web-search-sql-and-more-885</link>
      <guid>https://dev.to/venkatarahul27/i-built-an-ai-agent-with-claudes-tool-use-loop-web-search-sql-and-more-885</guid>
      <description>&lt;p&gt;"AI agent" gets thrown around so much I figured I should just build one instead of reading more threads about it. The core idea turned out to be small: you put Claude in a loop and hand it some tools. It picks a tool, you run it, you hand back the result, and it keeps going until it has an answer.&lt;/p&gt;

&lt;p&gt;Code is here if you want to skip ahead: &lt;a href="https://github.com/venkatarahul27/claude-research-agent" rel="noopener noreferrer"&gt;claude-research-agent&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can do
&lt;/h2&gt;

&lt;p&gt;Give it a task and it works out the steps on its own. Mine can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;search the web (no API key for this part, it just hits DuckDuckGo's HTML page)&lt;/li&gt;
&lt;li&gt;open a URL and pull the readable text out&lt;/li&gt;
&lt;li&gt;do math without me trusting &lt;code&gt;eval&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;run read-only SQL against a SQLite file&lt;/li&gt;
&lt;li&gt;read local files, but only inside the project folder&lt;/li&gt;
&lt;li&gt;save findings to a notes file&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The loop is basically the whole thing
&lt;/h2&gt;

&lt;p&gt;Honestly this is most of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;messages&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;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_message&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="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_STEPS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TOOL_SCHEMAS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;assistant&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop_reason&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_use&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;final_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;tool_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&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;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_use&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;run_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tool_results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;tool_result&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;tool_use_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tool_results&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thing to watch is &lt;code&gt;stop_reason&lt;/code&gt;. If Claude says &lt;code&gt;tool_use&lt;/code&gt;, it wants you to run something. You run it, drop the result back into the conversation as a &lt;code&gt;tool_result&lt;/code&gt;, and loop. When it stops asking for tools, you're done. The &lt;code&gt;MAX_STEPS&lt;/code&gt; cap is just there so a confused agent can't spin forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools are just functions
&lt;/h2&gt;

&lt;p&gt;Each tool is a Python function plus a little JSON schema telling Claude when to reach for it. Want a new capability? Write a function, add its schema. The loop never changes, which was the part I liked most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Guardrails, because this stuff can bite
&lt;/h2&gt;

&lt;p&gt;The second your agent can run code or touch a database, you have to be careful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the calculator parses an AST and only allows math, so something like &lt;code&gt;__import__("os")...&lt;/code&gt; gets rejected instead of run&lt;/li&gt;
&lt;li&gt;SQL is opened read-only and I block write keywords on top of that&lt;/li&gt;
&lt;li&gt;file reads can't escape the project folder, so no &lt;code&gt;../../etc/passwd&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skip this and you've basically built a foot-gun with a chat interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeing it actually run
&lt;/h2&gt;

&lt;p&gt;Here's a real run. I asked it to look up the latest Claude model and do some math, and it chained five tool calls by itself:&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="err"&gt;you&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Claude&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;model,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;calculate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2340&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="err"&gt;web_search(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest Claude model"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;calculator(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"expression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2340 * 0.15"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;fetch_url(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"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;"https://www.anthropic.com/news"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;save_note(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;agent&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2340&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;351&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;plus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;rundown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;models.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watching it decide the order on its own is the part that finally made "agent" click for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug that ate an hour
&lt;/h2&gt;

&lt;p&gt;My web search kept coming back empty even though the results were clearly in the HTML. Drove me a little crazy.&lt;/p&gt;

&lt;p&gt;Turns out DuckDuckGo wraps the matched words in &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt; tags inside each snippet. My parser was resetting its state on every closing tag, so the inner &lt;code&gt;&amp;lt;/b&amp;gt;&lt;/code&gt; wiped everything before the result ever got saved. The fix was to only reset on the closing &lt;code&gt;&amp;lt;/a&amp;gt;&lt;/code&gt; and flush the last result at the end. Classic "the real-world HTML is messier than your test case" moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to poke at it
&lt;/h2&gt;

&lt;p&gt;The repo has the CLI, a small FastAPI web UI that shows the tool trace, and a test suite: &lt;a href="https://github.com/venkatarahul27/claude-research-agent" rel="noopener noreferrer"&gt;github.com/venkatarahul27/claude-research-agent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Curious what tools other people would bolt on. I'm tempted to give it a real browser next.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>claude</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
