<?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: Natarajan Murugesan</title>
    <description>The latest articles on DEV Community by Natarajan Murugesan (@natarajan_murugesan_b00c4).</description>
    <link>https://dev.to/natarajan_murugesan_b00c4</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%2F3816382%2Ff3bdc1b8-af7e-4dae-97f3-fdfa09bdca77.jpg</url>
      <title>DEV Community: Natarajan Murugesan</title>
      <link>https://dev.to/natarajan_murugesan_b00c4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/natarajan_murugesan_b00c4"/>
    <language>en</language>
    <item>
      <title>AI Fluency for Software Engineers: A Practical Playbook Beyond Prompting</title>
      <dc:creator>Natarajan Murugesan</dc:creator>
      <pubDate>Fri, 12 Jun 2026 21:33:53 +0000</pubDate>
      <link>https://dev.to/natarajan_murugesan_b00c4/ai-fluency-for-software-engineers-a-practical-playbook-beyond-prompting-37n1</link>
      <guid>https://dev.to/natarajan_murugesan_b00c4/ai-fluency-for-software-engineers-a-practical-playbook-beyond-prompting-37n1</guid>
      <description>&lt;h2&gt;
  
  
  AI Fluency for Software Engineers: A Practical Playbook Beyond Prompting
&lt;/h2&gt;

&lt;p&gt;A few years ago, being productive with AI mostly meant knowing which tool to open and what question to ask.&lt;/p&gt;

&lt;p&gt;Today, that is not enough.&lt;/p&gt;

&lt;p&gt;For software engineers, AI is no longer just a chatbot sitting outside the workflow. It is becoming a thinking partner for architecture decisions, code reviews, production incidents, documentation, test planning, onboarding, and product discovery.&lt;/p&gt;

&lt;p&gt;But there is a problem: many teams are using powerful AI tools with weak operating habits.&lt;/p&gt;

&lt;p&gt;They ask vague questions. They paste too much context. They trust the first answer. They forget privacy boundaries. They use AI for speed, but not always for better engineering judgment.&lt;/p&gt;

&lt;p&gt;That is where &lt;strong&gt;AI fluency&lt;/strong&gt; matters.&lt;/p&gt;

&lt;p&gt;AI fluency is not just prompt engineering. It is the ability to work with AI clearly, safely, and practically while staying in control of quality, reasoning, and responsibility.&lt;/p&gt;

&lt;p&gt;Here is a practical playbook I would recommend for software engineers and engineering teams.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Start with clarity, not clever prompts
&lt;/h2&gt;

&lt;p&gt;A weak prompt sounds like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Review this design and tell me if it is good.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI can answer, but the answer will likely be generic.&lt;/p&gt;

&lt;p&gt;A stronger prompt gives the AI a clear role, context, constraints, and output format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a senior backend architect.

Review this proposed API design for a high-traffic order processing system.

Evaluate:
- correctness
- scalability
- failure handling
- observability
- backward compatibility
- operational complexity

Do not rewrite the whole design unless required.
Separate critical risks from optional improvements.

Output format:
- Executive summary
- Key risks
- Recommended changes
- Open questions
- Final decision recommendation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is not word count. The difference is control.&lt;/p&gt;

&lt;p&gt;A fluent AI user does not hope the AI understands the task. They make the task hard to misunderstand.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Give enough context, but not everything
&lt;/h2&gt;

&lt;p&gt;AI output quality depends heavily on context. Too little context gives generic answers. Too much context creates noise and can expose sensitive information.&lt;/p&gt;

&lt;p&gt;For example, imagine a team is considering micro-frontends because their frontend application has become large, slow to build, and difficult for multiple teams to work on independently.&lt;/p&gt;

&lt;p&gt;A weak question would be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Should we use micro-frontends?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A better question would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We have a large monolithic frontend used by several product teams.
Teams work in parallel across different functional domains.
Build time and deployment size are increasing.
We want better ownership and release flexibility.

Help us decide whether micro-frontends are the right approach.
Compare them with alternatives such as modular monolith, lazy-loaded modules, domain-based libraries, and build optimization.

Do not give a generic answer. Reason through trade-offs, team impact, CI/CD impact, runtime complexity, testing, and migration risk.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This kind of context makes the AI useful because it can reason against the real problem, not an abstract architecture trend.&lt;/p&gt;

&lt;p&gt;Good context usually includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;current situation&lt;/li&gt;
&lt;li&gt;business or technical goal&lt;/li&gt;
&lt;li&gt;audience&lt;/li&gt;
&lt;li&gt;constraints&lt;/li&gt;
&lt;li&gt;known problems&lt;/li&gt;
&lt;li&gt;options already considered&lt;/li&gt;
&lt;li&gt;what should not be included&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to dump everything. The goal is to provide the minimum useful context for a better answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Ask the AI to reason, not just answer
&lt;/h2&gt;

&lt;p&gt;One of the biggest AI fluency mistakes is asking for conclusions too early.&lt;/p&gt;

&lt;p&gt;For engineering work, the best AI outputs usually come when we ask the model to compare, challenge, and expose assumptions.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Which database should we use?”&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compare PostgreSQL, MongoDB, and DynamoDB for this use case.

Evaluate each option against:
- data model fit
- query patterns
- operational complexity
- cost
- team familiarity
- migration risk
- future flexibility

Separate known facts, assumptions, risks, and recommendation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is important because software engineering is rarely about one correct answer. It is about choosing the best trade-off under constraints.&lt;/p&gt;

&lt;p&gt;AI becomes more valuable when it helps us see those trade-offs clearly.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Treat the first answer as a draft
&lt;/h2&gt;

&lt;p&gt;The first AI response is rarely the final answer.&lt;/p&gt;

&lt;p&gt;Fluent users iterate.&lt;/p&gt;

&lt;p&gt;They say things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is useful, but still too generic.
Make it more practical for a team that has limited experience with this architecture.
Add migration steps, risk factors, learning curve, and a decision checklist.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rewrite this for engineering leadership.
Keep the technical accuracy, but focus more on risk, cost, delivery impact, and decision options.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add a table comparing the current approach with the proposed approach.
Include what improves, what remains the same, and what becomes more complex.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where AI starts becoming a real productivity multiplier. Not because the first answer is perfect, but because the refinement loop is fast.&lt;/p&gt;

&lt;p&gt;The skill is knowing how to push the AI from a general answer to a usable artifact.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Use AI safely during production incidents
&lt;/h2&gt;

&lt;p&gt;AI can help during incidents, but only with strong boundaries.&lt;/p&gt;

&lt;p&gt;Consider a production payment failure. Customers are blocked. The business is affected. Logs, traces, payment provider responses, and customer data may all be involved.&lt;/p&gt;

&lt;p&gt;This is not the time to paste raw production data into a random AI tool.&lt;/p&gt;

&lt;p&gt;A safe incident-analysis prompt should include clear rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a production incident analysis assistant.

Help analyze a payment failure incident using only sanitized logs, masked identifiers, synthetic examples, and approved read-only diagnostic outputs.

Do not request or expose customer PII, payment card data, secrets, tokens, credentials, or raw production payloads.

Separate:
- known facts
- hypotheses
- confidence level
- missing information
- recommended next actions

Do not recommend direct production changes without human approval.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the AI a controlled assistant, not an uncontrolled operator.&lt;/p&gt;

&lt;p&gt;In serious incidents, AI should support investigation, summarization, hypothesis generation, and runbook improvement. Humans should remain responsible for approval, production changes, and final root-cause confirmation.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Build reusable prompt patterns for the team
&lt;/h2&gt;

&lt;p&gt;AI fluency should not remain an individual skill. Teams should convert good prompts into reusable patterns.&lt;/p&gt;

&lt;p&gt;Useful team-level prompt templates include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;architecture decision review&lt;/li&gt;
&lt;li&gt;code review&lt;/li&gt;
&lt;li&gt;incident analysis&lt;/li&gt;
&lt;li&gt;pull request summary&lt;/li&gt;
&lt;li&gt;release note generation&lt;/li&gt;
&lt;li&gt;test case design&lt;/li&gt;
&lt;li&gt;onboarding documentation&lt;/li&gt;
&lt;li&gt;security review&lt;/li&gt;
&lt;li&gt;API design review&lt;/li&gt;
&lt;li&gt;postmortem draft&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, every architecture prompt can follow this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role:
You are a senior architect with experience in [domain].

Context:
[Current system, problem, constraints, team setup]

Task:
[Decision or review needed]

Evaluate:
[Scalability, complexity, cost, risk, maintainability, operations]

Rules:
Separate facts, assumptions, risks, and recommendation.
Do not assume missing information.

Output:
Decision matrix, recommendation, risks, migration path, open questions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When teams standardize patterns like this, AI usage becomes more consistent, safer, and easier to review.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. The real goal: better engineering judgment
&lt;/h2&gt;

&lt;p&gt;AI fluency is not about making engineers dependent on AI.&lt;/p&gt;

&lt;p&gt;It is about helping engineers think better, faster, and more clearly.&lt;/p&gt;

&lt;p&gt;A fluent engineer knows when to use AI for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;brainstorming&lt;/li&gt;
&lt;li&gt;summarization&lt;/li&gt;
&lt;li&gt;comparison&lt;/li&gt;
&lt;li&gt;documentation&lt;/li&gt;
&lt;li&gt;test planning&lt;/li&gt;
&lt;li&gt;debugging support&lt;/li&gt;
&lt;li&gt;learning unfamiliar topics&lt;/li&gt;
&lt;li&gt;preparing decision records&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They also know when not to use AI blindly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;final security decisions&lt;/li&gt;
&lt;li&gt;legal or compliance conclusions&lt;/li&gt;
&lt;li&gt;production changes&lt;/li&gt;
&lt;li&gt;sensitive data analysis&lt;/li&gt;
&lt;li&gt;performance claims without measurement&lt;/li&gt;
&lt;li&gt;architecture decisions without team context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best AI users are not the ones who ask the most prompts.&lt;/p&gt;

&lt;p&gt;They are the ones who can combine domain knowledge, context, constraints, validation, and iteration into a disciplined workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;For software engineers, AI fluency has five core habits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Be clear&lt;/strong&gt; about the role, task, context, and output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share context carefully&lt;/strong&gt; without leaking sensitive information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask for reasoning&lt;/strong&gt;, not just answers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate deliberately&lt;/strong&gt; until the output becomes useful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use AI safely&lt;/strong&gt;, especially around production, customer data, and business-critical systems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AI will not replace engineering judgment.&lt;/p&gt;

&lt;p&gt;But engineers who learn to work fluently with AI will make better decisions, create better documentation, review systems faster, and communicate complex ideas more clearly.&lt;/p&gt;

&lt;p&gt;That is the real value of AI fluency.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>productivity</category>
      <category>promptengineering</category>
    </item>
    <item>
      <title>Why I Am Building Rudhra as an Agent Operating Platform</title>
      <dc:creator>Natarajan Murugesan</dc:creator>
      <pubDate>Thu, 11 Jun 2026 22:31:34 +0000</pubDate>
      <link>https://dev.to/natarajan_murugesan_b00c4/why-i-am-building-rudhra-as-an-agent-operating-platform-34og</link>
      <guid>https://dev.to/natarajan_murugesan_b00c4/why-i-am-building-rudhra-as-an-agent-operating-platform-34og</guid>
      <description>&lt;p&gt;AI agents are moving fast.&lt;/p&gt;

&lt;p&gt;Every week, new frameworks, models, tools, and patterns appear. Developers can now build agents that reason, call tools, retrieve knowledge, interact with APIs, automate workflows, and collaborate with other agents.&lt;/p&gt;

&lt;p&gt;But after building several real-world agent experiments, one thing became clear to me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Creating an agent is becoming easier. Operating an agent responsibly in production is still hard.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the problem I am working on with &lt;strong&gt;Rudhra&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Rudhra is an Agent Operating Platform.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is designed to help teams build, govern, evaluate, deploy, observe, and operate AI agents across multiple execution engines.&lt;/p&gt;

&lt;p&gt;Instead of treating agents as isolated scripts or one-off prototypes, Rudhra focuses on the full lifecycle of production agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;defining agents clearly&lt;/li&gt;
&lt;li&gt;managing versions&lt;/li&gt;
&lt;li&gt;connecting approved tools and data sources&lt;/li&gt;
&lt;li&gt;enforcing approval workflows&lt;/li&gt;
&lt;li&gt;running evaluations&lt;/li&gt;
&lt;li&gt;tracking executions&lt;/li&gt;
&lt;li&gt;observing traces and outcomes&lt;/li&gt;
&lt;li&gt;supporting multiple products and workspaces&lt;/li&gt;
&lt;li&gt;making agents reusable and governable&lt;/li&gt;
&lt;/ul&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Help teams move from agent prototypes to reliable, observable, and governable agent-powered products.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why an Agent Operating Platform?
&lt;/h2&gt;

&lt;p&gt;Most AI agent work today starts with a framework.&lt;/p&gt;

&lt;p&gt;Frameworks are important. They help developers build agents faster.&lt;/p&gt;

&lt;p&gt;There are excellent tools in this space, including graph-based runtimes, tool-calling frameworks, multi-agent frameworks, cloud-native agent development kits, and enterprise AI orchestration SDKs.&lt;/p&gt;

&lt;p&gt;But a framework usually answers questions like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do I build this agent?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A platform needs to answer broader production questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who owns this agent?&lt;br&gt;&lt;br&gt;
Which version is running?&lt;br&gt;&lt;br&gt;
Which tools can it use?&lt;br&gt;&lt;br&gt;
Which data sources can it access?&lt;br&gt;&lt;br&gt;
Which actions require human approval?&lt;br&gt;&lt;br&gt;
Which evaluations passed before release?&lt;br&gt;&lt;br&gt;
What happened during a specific run?&lt;br&gt;&lt;br&gt;
Can we debug, audit, rollback, and improve it safely?&lt;br&gt;&lt;br&gt;
Can the same operating model support agents across multiple products?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is where Rudhra is positioned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rudhra is not just another agent framework
&lt;/h2&gt;

&lt;p&gt;Rudhra is not intended to replace every agent framework.&lt;/p&gt;

&lt;p&gt;Instead, Rudhra is designed to sit above execution engines and provide a consistent operating layer.&lt;/p&gt;

&lt;p&gt;In the future, a Rudhra agent should be able to run on one or more execution engines, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;native Rudhra runtime&lt;/li&gt;
&lt;li&gt;graph-based agent runtimes&lt;/li&gt;
&lt;li&gt;tool-calling frameworks&lt;/li&gt;
&lt;li&gt;multi-agent frameworks&lt;/li&gt;
&lt;li&gt;cloud-native agent development kits&lt;/li&gt;
&lt;li&gt;enterprise AI orchestration frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The execution engine can change.&lt;/p&gt;

&lt;p&gt;The operating layer should remain consistent.&lt;/p&gt;

&lt;p&gt;That means Rudhra focuses on the platform concerns around agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agent registry&lt;/li&gt;
&lt;li&gt;tool registry&lt;/li&gt;
&lt;li&gt;connector registry&lt;/li&gt;
&lt;li&gt;workspace ownership&lt;/li&gt;
&lt;li&gt;approval policies&lt;/li&gt;
&lt;li&gt;evaluation gates&lt;/li&gt;
&lt;li&gt;run history&lt;/li&gt;
&lt;li&gt;trace visibility&lt;/li&gt;
&lt;li&gt;lifecycle management&lt;/li&gt;
&lt;li&gt;Studio-based observability&lt;/li&gt;
&lt;li&gt;reusable agent specifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes Rudhra an operating platform rather than only a coding framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real problem: production readiness
&lt;/h2&gt;

&lt;p&gt;Many agent demos look impressive.&lt;/p&gt;

&lt;p&gt;But production environments need more than demos.&lt;/p&gt;

&lt;p&gt;A production agent needs discipline around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;security&lt;/li&gt;
&lt;li&gt;permissions&lt;/li&gt;
&lt;li&gt;data access&lt;/li&gt;
&lt;li&gt;human approval&lt;/li&gt;
&lt;li&gt;cost control&lt;/li&gt;
&lt;li&gt;versioning&lt;/li&gt;
&lt;li&gt;observability&lt;/li&gt;
&lt;li&gt;testing&lt;/li&gt;
&lt;li&gt;evaluation&lt;/li&gt;
&lt;li&gt;failure handling&lt;/li&gt;
&lt;li&gt;auditability&lt;/li&gt;
&lt;li&gt;rollback&lt;/li&gt;
&lt;li&gt;maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without these, agents can become difficult to trust, difficult to debug, and difficult to scale across teams.&lt;/p&gt;

&lt;p&gt;Rudhra is being built to close that gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Rudhra can help
&lt;/h2&gt;

&lt;p&gt;Rudhra is useful when agents are not just experiments, but part of real business workflows.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a food business using agents for menu planning, customer communication, and operational workflows&lt;/li&gt;
&lt;li&gt;a learning platform using agents for content generation, pronunciation support, and personalized practice&lt;/li&gt;
&lt;li&gt;internal enterprise tools using agents for documentation, support, migration, reporting, and automation&lt;/li&gt;
&lt;li&gt;personal productivity agents that need safe access to tools, calendars, emails, or knowledge sources&lt;/li&gt;
&lt;li&gt;product teams that want agent capabilities without losing engineering governance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common requirement is not just intelligence.&lt;/p&gt;

&lt;p&gt;The common requirement is &lt;strong&gt;controlled operation&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  My focus
&lt;/h2&gt;

&lt;p&gt;My background is in full-stack engineering, platform modernization, Java, Spring Boot, Angular, microservices, legacy system migration, and applied AI engineering.&lt;/p&gt;

&lt;p&gt;With Rudhra, I am combining those areas into one direction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Building a practical operating platform for production AI agents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The focus is not only on what an agent can generate.&lt;/p&gt;

&lt;p&gt;The focus is also on how that agent is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;designed&lt;/li&gt;
&lt;li&gt;configured&lt;/li&gt;
&lt;li&gt;validated&lt;/li&gt;
&lt;li&gt;approved&lt;/li&gt;
&lt;li&gt;executed&lt;/li&gt;
&lt;li&gt;monitored&lt;/li&gt;
&lt;li&gt;improved&lt;/li&gt;
&lt;li&gt;reused&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where traditional software engineering discipline and agentic AI need to meet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The direction
&lt;/h2&gt;

&lt;p&gt;Rudhra is evolving around a few important principles.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Agents should be versioned software assets
&lt;/h3&gt;

&lt;p&gt;Agents should not be invisible prompt scripts hidden inside applications.&lt;/p&gt;

&lt;p&gt;They should have identity, version, ownership, lifecycle, and release discipline.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Tools and connectors should be governed
&lt;/h3&gt;

&lt;p&gt;Agents should not get uncontrolled access to business systems.&lt;/p&gt;

&lt;p&gt;Tool usage and data access need clear boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Human approval should be built in
&lt;/h3&gt;

&lt;p&gt;For important actions, the platform should support approval before execution, publishing, sending, or dispatching.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Evaluation should be part of the lifecycle
&lt;/h3&gt;

&lt;p&gt;Before agents are promoted, they should pass meaningful evaluation scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Observability should be standard
&lt;/h3&gt;

&lt;p&gt;Every run should be traceable enough to understand what happened, why it happened, and how it can be improved.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. The platform should support multiple engines
&lt;/h3&gt;

&lt;p&gt;Teams should not be locked into a single agent framework.&lt;/p&gt;

&lt;p&gt;Rudhra should provide a consistent operating layer while allowing different execution engines behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I am building in this direction
&lt;/h2&gt;

&lt;p&gt;AI agents will become part of many products.&lt;/p&gt;

&lt;p&gt;But organizations will need a way to operate them safely and consistently.&lt;/p&gt;

&lt;p&gt;The next challenge is not only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we build an agent?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next challenge is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we operate many agents across products, teams, tools, and workflows with trust?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the direction of Rudhra.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Agents are becoming easier to create.&lt;/p&gt;

&lt;p&gt;But production agents need an operating layer.&lt;/p&gt;

&lt;p&gt;That is why I am building &lt;strong&gt;Rudhra — an Agent Operating Platform for building, governing, evaluating, deploying, observing, and operating AI agents across multiple execution engines.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>platformengineering</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Build a Practical AI Agent with Gemma 4, Real Tools, and a Local LLM</title>
      <dc:creator>Natarajan Murugesan</dc:creator>
      <pubDate>Sat, 11 Apr 2026 19:35:38 +0000</pubDate>
      <link>https://dev.to/natarajan_murugesan_b00c4/build-a-practical-ai-agent-with-gemma-4-real-tools-and-a-local-llm-31k4</link>
      <guid>https://dev.to/natarajan_murugesan_b00c4/build-a-practical-ai-agent-with-gemma-4-real-tools-and-a-local-llm-31k4</guid>
      <description>&lt;h2&gt;
  
  
  Build a Practical AI Agent with Real Tools and a Local LLM
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;How to combine Tavily, OpenWeatherMap, and LangGraph into a clean local-first workflow&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most local LLM demos are either too simple to be useful or too complex to reuse.&lt;/p&gt;

&lt;p&gt;I wanted something in the middle: a practical AI agent that can search the web, check live weather, and still keep the reasoning layer local. So I built a workflow using LangGraph, Tavily, OpenWeatherMap, and a local LLM running through Ollama.&lt;/p&gt;

&lt;p&gt;The result is a clean local-first architecture where tools provide real-time facts and the model turns them into useful answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Local LLMs are great for privacy, experimentation, and cost control. But on their own, they do not know live weather or fresh web results.&lt;/p&gt;

&lt;p&gt;That is where external tools become valuable.&lt;/p&gt;

&lt;p&gt;In this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tavily provides current web search results&lt;/li&gt;
&lt;li&gt;OpenWeatherMap provides live weather data&lt;/li&gt;
&lt;li&gt;the local LLM handles reasoning and phrasing&lt;/li&gt;
&lt;li&gt;LangGraph orchestrates the workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This combination creates something much more useful than a plain local chatbot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture at a Glance
&lt;/h2&gt;

&lt;p&gt;Before looking at the code, here is the core workflow.&lt;/p&gt;

&lt;p&gt;Rather than asking the model to do everything in one opaque step, I split the system into clear responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;router node&lt;/strong&gt; decides what kind of request it is&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;Tavily node&lt;/strong&gt; fetches fresh web results&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;OpenWeatherMap node&lt;/strong&gt; fetches live weather data&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;local LLM node&lt;/strong&gt; combines those results into the final answer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes the system easier to debug, easier to extend, and much easier to reason about.&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%2Flrn4fsyhl3lt2npvwlfb.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%2Flrn4fsyhl3lt2npvwlfb.png" alt=" " width="800" height="711"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key design principle is simple: &lt;strong&gt;tools provide facts, the local LLM provides reasoning&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this architecture works
&lt;/h2&gt;

&lt;p&gt;This pattern works because it separates responsibility cleanly.&lt;/p&gt;

&lt;p&gt;The model is no longer expected to hallucinate current weather or pretend it knows the latest web information. Instead, tools provide live facts and the LLM focuses on synthesis, reasoning, and response generation.&lt;/p&gt;

&lt;p&gt;That separation makes the system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more reliable&lt;/li&gt;
&lt;li&gt;easier to debug&lt;/li&gt;
&lt;li&gt;easier to evolve over time&lt;/li&gt;
&lt;li&gt;more practical for real applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example use cases
&lt;/h2&gt;

&lt;p&gt;This kind of agent can answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“What is LangGraph and why is it useful?”&lt;/li&gt;
&lt;li&gt;“What is the weather in Amsterdam today?”&lt;/li&gt;
&lt;li&gt;“Summarize today’s AI news and tell me whether I need a jacket this evening.”&lt;/li&gt;
&lt;li&gt;“Give me a quick weather summary and travel advice for Rotterdam.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is where the stack becomes more interesting than a typical chatbot.&lt;/p&gt;

&lt;h2&gt;
  
  
  State schema
&lt;/h2&gt;

&lt;p&gt;A simple state schema can look like this:&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;typing_extensions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypedDict&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;search_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;weather_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the workflow explicit and makes it easier to inspect what each node is contributing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Router node
&lt;/h2&gt;

&lt;p&gt;The router decides whether the request needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;web search&lt;/li&gt;
&lt;li&gt;weather lookup&lt;/li&gt;
&lt;li&gt;both&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a simple keyword-based version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;router_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;has_weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather&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;temperature&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;rain&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;forecast&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;jacket&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;has_search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what is&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;latest&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;news&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;search&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;explain&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;why&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;if&lt;/span&gt; &lt;span class="n"&gt;has_weather&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;has_search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;intent&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;both&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;has_weather&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;intent&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;weather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;intent&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;search&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;This is intentionally simple. A more advanced version could use an LLM-based classifier or structured intent routing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tavily search node
&lt;/h2&gt;

&lt;p&gt;Tavily is a clean option for search in AI workflows because it returns structured results that are easy to pass into the next node.&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;tavily&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TavilyClient&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;tavily&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TavilyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TAVILY_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tavily_search_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AgentState&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="n"&gt;tavily&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;general&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_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;lines&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;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
        &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&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="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&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="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lines&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;URL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Snippet: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;snippet&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_results&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="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This node is responsible only for search. It does not try to answer the question yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenWeatherMap node
&lt;/h2&gt;

&lt;p&gt;The OpenWeatherMap node handles live weather data. In this version, the city is resolved to coordinates first, and then current weather is fetched.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;OPENWEATHER_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENWEATHER_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_coordinates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://api.openweathermap.org/geo/1.0/direct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&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;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;appid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OPENWEATHER_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&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="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No coordinates found for city: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country&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="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;openweather_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Amsterdam,NL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lon&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;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_coordinates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.openweathermap.org/data/2.5/weather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&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;lat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;appid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OPENWEATHER_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;units&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;metric&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;
Location: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
Temperature: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; °C
Feels like: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feels_like&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; °C
Condition: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
Humidity: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;humidity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%
Wind speed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wind&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;speed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; m/s
&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This node only retrieves and formats facts. It does not do interpretation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local LLM answer node
&lt;/h2&gt;

&lt;p&gt;Once the tool results are available, the local LLM can turn them into a useful final answer.&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;langchain_ollama&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatOllama&lt;/span&gt;

&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatOllama&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;gemma4:e4b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# replace with your local gemma4 tag if available
&lt;/span&gt;    &lt;span class="n"&gt;temperature&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="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;answer_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;
You are a helpful AI assistant.

Use the available tool results below to answer the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s request clearly.

User request:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

Web search results:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

Weather data:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&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="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the point where the local model adds value. It is not fetching data. It is turning tool outputs into a coherent response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the LangGraph workflow
&lt;/h2&gt;

&lt;p&gt;Here is how the graph can be wired together:&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;langgraph.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;router&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;router_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tavily_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tavily_search_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openweather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;openweather_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answer_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;router&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;route_after_router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AgentState&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;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;intent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;router&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;route_after_router&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;search&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;tavily_search&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;weather&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;openweather&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;both&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;tavily_search&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="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tavily_search&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;openweather&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openweather&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;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This version keeps the orchestration explicit. You can easily expand it later with retries, memory, more tools, or better routing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&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_input&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;Summarize today&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s AI news and tell me if I need a jacket in Amsterdam&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;intent&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="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&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;Amsterdam,NL&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;search_results&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="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather_data&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="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example output
&lt;/h2&gt;

&lt;p&gt;For a weather-related prompt, the agent produced this response:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The weather in Amsterdam today is expected to be a &lt;strong&gt;clear sky&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Temperature:&lt;/strong&gt; 9.22 °C
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feels like:&lt;/strong&gt; 4.85 °C
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wind speed:&lt;/strong&gt; 11.62 m/s
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Humidity:&lt;/strong&gt; 71%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Should you carry a jacket?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes. The wind makes it feel significantly colder than the actual temperature, so a jacket is definitely recommended.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is exactly the kind of output I was aiming for: not just raw tool data, but a useful, human-readable answer grounded in live information.&lt;/p&gt;

&lt;p&gt;At that point, the agent can combine fresh web information, live weather data, and local reasoning in one workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I like this pattern
&lt;/h2&gt;

&lt;p&gt;For me, this is where local LLMs become much more interesting.&lt;/p&gt;

&lt;p&gt;Not as isolated chatbots.&lt;br&gt;
Not as black-box “agents.”&lt;br&gt;
But as reasoning layers connected to real tools.&lt;/p&gt;

&lt;p&gt;This pattern gives me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local-first reasoning&lt;/li&gt;
&lt;li&gt;explicit orchestration&lt;/li&gt;
&lt;li&gt;practical utility&lt;/li&gt;
&lt;li&gt;easier debugging&lt;/li&gt;
&lt;li&gt;a strong path for extension&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes it useful both as a learning project and as a foundation for more advanced AI applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This project reminded me that useful AI agents do not need to be huge or mysterious.&lt;/p&gt;

&lt;p&gt;A small graph, a couple of well-chosen tools, and a local LLM are enough to build something genuinely practical.&lt;/p&gt;

&lt;p&gt;LangGraph gives the structure. Tavily and OpenWeatherMap provide live facts. The local model turns those facts into useful answers.&lt;/p&gt;

&lt;p&gt;That feels like a strong foundation for local-first AI systems.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>langgraph</category>
      <category>ollama</category>
      <category>python</category>
    </item>
    <item>
      <title>Stop met tokens verspillen in OpenClaw</title>
      <dc:creator>Natarajan Murugesan</dc:creator>
      <pubDate>Sun, 15 Mar 2026 10:58:02 +0000</pubDate>
      <link>https://dev.to/natarajan_murugesan_b00c4/stop-met-tokens-verspillen-in-openclaw-39oe</link>
      <guid>https://dev.to/natarajan_murugesan_b00c4/stop-met-tokens-verspillen-in-openclaw-39oe</guid>
      <description>&lt;h2&gt;
  
  
  OpenClaw Agents: verlaag LLM-kosten zonder kwaliteit op te offeren
&lt;/h2&gt;

&lt;p&gt;De meeste teams proberen LLM-kosten te verlagen door prompts korter te maken, outputs in te korten of goedkopere modellen te gebruiken.&lt;/p&gt;

&lt;p&gt;Dat helpt een beetje.&lt;/p&gt;

&lt;p&gt;Maar in echte OpenClaw-omgevingen komt de grootste verspilling meestal ergens anders vandaan: &lt;strong&gt;inefficiënt runtime-gedrag&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Kapotte fallback-ketens, provider/auth-mismatches, verouderde sessiecontext en inconsistente agentconfiguraties kunnen ongemerkt zorgen voor meer retries, hoger tokengebruik, meer latency en ruis in logs.&lt;/p&gt;

&lt;p&gt;De praktische les is simpel:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Optimaliseer eerst runtime-gedrag. Optimaliseer prompts daarna.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Waar de extra kosten meestal vandaan komen
&lt;/h2&gt;

&lt;p&gt;In veel OpenClaw-deployments wordt vermijdbare uitgave veroorzaakt door:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gemengde model/provider-routing&lt;/li&gt;
&lt;li&gt;fallbacks die wel geconfigureerd zijn, maar in de praktijk niet werken&lt;/li&gt;
&lt;li&gt;langlevende sessies die oude geschiedenis meenemen&lt;/li&gt;
&lt;li&gt;verschillende instellingen tussen vergelijkbare agents&lt;/li&gt;
&lt;li&gt;terugkerende auth-, failover- of timeoutproblemen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deze problemen creëren verborgen overhead nog vóórdat het model überhaupt een antwoord genereert.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wat je als eerste moet oplossen
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Gebruik één geldige geauthenticeerde route
&lt;/h3&gt;

&lt;p&gt;Je primaire model moet overeenkomen met de credentials die de agent daadwerkelijk heeft.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stel een geldige &lt;code&gt;model.primary&lt;/code&gt; in&lt;/li&gt;
&lt;li&gt;Verwijder fallbacks die afhankelijk zijn van ontbrekende credentials&lt;/li&gt;
&lt;li&gt;Houd routing deterministisch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alleen dit al kan mislukte pogingen en rumoerige uitvoerpaden verminderen.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Houd fallback-ontwerp minimaal
&lt;/h3&gt;

&lt;p&gt;Fallback is bedoeld voor veerkracht, niet voor normale routing.&lt;/p&gt;

&lt;p&gt;Een goede vuistregel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;houd de fallback-lijst op &lt;code&gt;0–2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;neem alleen geteste, bruikbare entries op&lt;/li&gt;
&lt;li&gt;vermijd cross-provider fallback tenzij die volledig ondersteund wordt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lange fallback-ketens verhogen de kosten vaak meer dan dat ze risico verlagen.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Beperk de groei van context
&lt;/h3&gt;

&lt;p&gt;Verouderde geschiedenis verhoogt stilletjes het aantal inputtokens.&lt;/p&gt;

&lt;p&gt;Een praktisch patroon is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;contextPruning.mode = cache-ttl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contextPruning.ttl = 5m&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;compaction.mode = safeguard&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dit helpt prompt-bloat te voorkomen in chatintensieve omgevingen.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Reset inactieve sessies
&lt;/h3&gt;

&lt;p&gt;Als sessies te lang actief blijven, blijven ze oude context meeslepen.&lt;/p&gt;

&lt;p&gt;Een nuttige instelling is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;session.reset.idleMinutes = 15&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maak ook verouderde sessies leeg na grote configuratiewijzigingen, zodat oude metadata nieuwe runs niet beïnvloedt.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Lijn multi-agentbeleid op elkaar af
&lt;/h3&gt;

&lt;p&gt;Als meerdere agents vergelijkbaar werk doen, houd ze dan op hetzelfde routing- en sessiebeleid, tenzij er een echte reden is om daarvan af te wijken.&lt;/p&gt;

&lt;p&gt;Dat maakt gedrag voorspelbaarder over Slack, Telegram of andere kanalen heen.&lt;/p&gt;




&lt;h2&gt;
  
  
  Oud versus nieuw
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimensie&lt;/th&gt;
&lt;th&gt;Oud gedrag&lt;/th&gt;
&lt;th&gt;Geoptimaliseerd gedrag&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Primaire routing&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Gemengde routes&lt;/td&gt;
&lt;td&gt;Eén geauthenticeerde route&lt;/td&gt;
&lt;td&gt;Duidelijk uitvoerpad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Fallback-afhandeling&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Ongeldige fallback-pogingen&lt;/td&gt;
&lt;td&gt;Kapotte fallback verwijderd&lt;/td&gt;
&lt;td&gt;Minder retry-verspilling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Foutpatroon&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Terugkerende auth/failover-ruis&lt;/td&gt;
&lt;td&gt;Schonere logs&lt;/td&gt;
&lt;td&gt;Makkelijkere triage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Contexttrend&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Blijft groeien&lt;/td&gt;
&lt;td&gt;TTL pruning + compaction&lt;/td&gt;
&lt;td&gt;Minder prompt-bloat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Idle-gedrag&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Verouderde sessies blijven bestaan&lt;/td&gt;
&lt;td&gt;Idle reset na 15 min&lt;/td&gt;
&lt;td&gt;Lager basis-tokengebruik&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Agentconsistentie&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Drift tussen agents&lt;/td&gt;
&lt;td&gt;Gedeeld beleid&lt;/td&gt;
&lt;td&gt;Voorspelbaardere operaties&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Hoe je de wijziging valideert
&lt;/h2&gt;

&lt;p&gt;Na het bijwerken van de configuratie:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;voer &lt;code&gt;openclaw status&lt;/code&gt; uit&lt;/li&gt;
&lt;li&gt;bevestig de actieve modelroute&lt;/li&gt;
&lt;li&gt;bekijk enkele minuten de logs&lt;/li&gt;
&lt;li&gt;controleer op auth-fouten, failovers en timeouts&lt;/li&gt;
&lt;li&gt;verifieer dat nieuwe sessies schoon starten&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Een configuratie kan er correct uitzien en toch nog tokens verspillen tijdens runtime, dus validatie is belangrijk.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wat je moet meten
&lt;/h2&gt;

&lt;p&gt;Een eenvoudige KPI-set is al voldoende:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gemiddeld aantal inputtokens per beurt&lt;/li&gt;
&lt;li&gt;aantal failover-fouten per dag&lt;/li&gt;
&lt;li&gt;aantal auth-mismatches per dag&lt;/li&gt;
&lt;li&gt;aantal timeouts per dag&lt;/li&gt;
&lt;li&gt;cache read ratio&lt;/li&gt;
&lt;li&gt;kosten per 100 gesprekken&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nuttige formules:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token-efficiëntie&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nuttige antwoorden / Totaal aantal inputtokens
(Mislukte pogingen / Totaal aantal pogingen) * 100
((Huidige week - Vorige week) / Vorige week) * 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Aanbevolen reviewritme:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dagelijks:&lt;/strong&gt; fouten en timeouts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wekelijks:&lt;/strong&gt; token- en kostentrends&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maandelijks:&lt;/strong&gt; routingbeleid en modelreview&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Belangrijkste conclusie
&lt;/h2&gt;

&lt;p&gt;Kostenverlaging in OpenClaw is meestal niet eerst een promptprobleem.&lt;/p&gt;

&lt;p&gt;Het is een probleem van uitvoeringsdiscipline.&lt;/p&gt;

&lt;p&gt;De grootste besparingen komen meestal van:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;model/provider/auth-afstemming&lt;/li&gt;
&lt;li&gt;kort en geldig fallback-ontwerp&lt;/li&gt;
&lt;li&gt;context pruning en compaction&lt;/li&gt;
&lt;li&gt;sessie-resetbeleid&lt;/li&gt;
&lt;li&gt;consistentie tussen agents&lt;/li&gt;
&lt;li&gt;doorlopende meting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Als je die dingen eerst oplost, krijg je meestal tegelijk lagere kosten, meer stabiliteit en eenvoudiger beheer.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>openclaw</category>
    </item>
    <item>
      <title>Stop Wasting Tokens in OpenClaw</title>
      <dc:creator>Natarajan Murugesan</dc:creator>
      <pubDate>Sat, 14 Mar 2026 23:11:57 +0000</pubDate>
      <link>https://dev.to/natarajan_murugesan_b00c4/stop-wasting-tokens-in-openclaw-5757</link>
      <guid>https://dev.to/natarajan_murugesan_b00c4/stop-wasting-tokens-in-openclaw-5757</guid>
      <description>&lt;h2&gt;
  
  
  OpenClaw Agents: Reduce LLM Cost Without Sacrificing Quality
&lt;/h2&gt;

&lt;p&gt;Most teams try to reduce LLM cost by shortening prompts, cutting output length, or switching to cheaper models.&lt;/p&gt;

&lt;p&gt;That can help a little.&lt;/p&gt;

&lt;p&gt;But in real OpenClaw setups, the biggest waste usually comes from somewhere else: &lt;strong&gt;runtime inefficiency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Broken fallback chains, provider/auth mismatch, stale session context, and inconsistent agent configuration can quietly increase retries, token usage, latency, and log noise.&lt;/p&gt;

&lt;p&gt;The practical lesson is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Optimize runtime behavior first. Optimize prompts second.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Where the extra cost usually comes from
&lt;/h2&gt;

&lt;p&gt;In many OpenClaw deployments, avoidable spend is caused by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mixed model/provider routing&lt;/li&gt;
&lt;li&gt;fallbacks that are configured but cannot actually run&lt;/li&gt;
&lt;li&gt;long-lived sessions carrying stale history&lt;/li&gt;
&lt;li&gt;different settings across similar agents&lt;/li&gt;
&lt;li&gt;repeated auth, failover, or timeout issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These problems create hidden overhead before the model even generates a response.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to fix first
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Use one valid authenticated lane
&lt;/h3&gt;

&lt;p&gt;Your primary model should match the credentials the agent actually has.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set a valid &lt;code&gt;model.primary&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Remove fallbacks that depend on missing credentials&lt;/li&gt;
&lt;li&gt;Keep routing deterministic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This alone can reduce failed attempts and noisy execution paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Keep fallback design minimal
&lt;/h3&gt;

&lt;p&gt;Fallback should be for resilience, not normal routing.&lt;/p&gt;

&lt;p&gt;A good rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep fallback list to &lt;code&gt;0–2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;only include tested, usable entries&lt;/li&gt;
&lt;li&gt;avoid cross-provider fallback unless fully supported&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Long fallback chains often increase cost more than they reduce risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Control context growth
&lt;/h3&gt;

&lt;p&gt;Stale history silently increases input tokens.&lt;/p&gt;

&lt;p&gt;A practical pattern is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;contextPruning.mode = cache-ttl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contextPruning.ttl = 5m&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;compaction.mode = safeguard&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps prevent prompt bloat in chat-heavy environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Reset idle sessions
&lt;/h3&gt;

&lt;p&gt;If sessions stay alive too long, they keep dragging old context forward.&lt;/p&gt;

&lt;p&gt;A useful setting is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;session.reset.idleMinutes = 15&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also clear stale sessions after major config changes so old metadata does not affect new runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Align multi-agent policy
&lt;/h3&gt;

&lt;p&gt;If multiple agents do similar work, keep them on the same routing and session policy unless there is a real reason to differ.&lt;/p&gt;

&lt;p&gt;That makes behavior more predictable across Slack, Telegram, or other channels.&lt;/p&gt;




&lt;h2&gt;
  
  
  Old vs New
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Old behavior&lt;/th&gt;
&lt;th&gt;Optimized behavior&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;em&gt;Primary routing&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mixed lanes&lt;/td&gt;
&lt;td&gt;Single authenticated lane&lt;/td&gt;
&lt;td&gt;Clear execution path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;em&gt;Fallback handling&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Invalid fallback attempts&lt;/td&gt;
&lt;td&gt;Broken fallback removed&lt;/td&gt;
&lt;td&gt;Less retry waste&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;em&gt;Error pattern&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recurring auth/failover noise&lt;/td&gt;
&lt;td&gt;Cleaner logs&lt;/td&gt;
&lt;td&gt;Easier triage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;em&gt;Context trend&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Keeps growing&lt;/td&gt;
&lt;td&gt;TTL pruning + compaction&lt;/td&gt;
&lt;td&gt;Lower prompt bloat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;em&gt;Idle behavior&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stale sessions persist&lt;/td&gt;
&lt;td&gt;Idle reset at 15 min&lt;/td&gt;
&lt;td&gt;Lower baseline token use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;em&gt;Agent consistency&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Drift between agents&lt;/td&gt;
&lt;td&gt;Shared policy&lt;/td&gt;
&lt;td&gt;Predictable operations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How to validate the change
&lt;/h2&gt;

&lt;p&gt;After updating config:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run &lt;code&gt;openclaw status&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;confirm the active model lane&lt;/li&gt;
&lt;li&gt;watch logs for a few minutes&lt;/li&gt;
&lt;li&gt;check for auth errors, failovers, and timeouts&lt;/li&gt;
&lt;li&gt;verify new sessions start clean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A config can look correct and still waste tokens in runtime, so validation matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to measure
&lt;/h2&gt;

&lt;p&gt;A simple KPI set is enough:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;avg input tokens per turn&lt;/li&gt;
&lt;li&gt;failover errors per day&lt;/li&gt;
&lt;li&gt;auth mismatch errors per day&lt;/li&gt;
&lt;li&gt;timeouts per day&lt;/li&gt;
&lt;li&gt;cache read ratio&lt;/li&gt;
&lt;li&gt;cost per 100 conversations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful formulas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token efficiency&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Useful responses / Total input tokens
(Failed attempts / Total attempts) * 100
((Current week - Previous week) / Previous week) * 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suggested review cadence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily:&lt;/strong&gt; errors and timeouts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekly:&lt;/strong&gt; token and cost trend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly:&lt;/strong&gt; routing policy and model review&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;OpenClaw cost reduction is usually not a prompt problem first.&lt;/p&gt;

&lt;p&gt;It is an execution-discipline problem.&lt;/p&gt;

&lt;p&gt;The biggest savings usually come from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model/provider/auth alignment&lt;/li&gt;
&lt;li&gt;Short and valid fallback design&lt;/li&gt;
&lt;li&gt;Context pruning and compaction&lt;/li&gt;
&lt;li&gt;Session reset policy&lt;/li&gt;
&lt;li&gt;Multi-agent consistency&lt;/li&gt;
&lt;li&gt;Ongoing measurement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you fix those first, you usually get lower cost, better stability, and easier operations at the same time.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openclaw</category>
      <category>agents</category>
      <category>llm</category>
    </item>
    <item>
      <title>Building Multi-Agent Slack Routing with OpenClaw</title>
      <dc:creator>Natarajan Murugesan</dc:creator>
      <pubDate>Tue, 10 Mar 2026 08:46:34 +0000</pubDate>
      <link>https://dev.to/natarajan_murugesan_b00c4/building-multi-agent-slack-routing-with-openclaw-4n5o</link>
      <guid>https://dev.to/natarajan_murugesan_b00c4/building-multi-agent-slack-routing-with-openclaw-4n5o</guid>
      <description>&lt;p&gt;As AI systems evolve, a single assistant is often not enough. Many workflows benefit from multiple specialized agents — each with its own personality, capabilities, and routing logic.&lt;/p&gt;

&lt;p&gt;Recently I experimented with OpenClaw to build a multi-agent Slack integration, where different Slack accounts route conversations to different agents.&lt;/p&gt;

&lt;p&gt;This mini post summarizes the key learnings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Setup in OpenClaw
&lt;/h2&gt;

&lt;p&gt;The first step was creating two agents:&lt;/p&gt;

&lt;p&gt;main – default assistant&lt;/p&gt;

&lt;p&gt;nila – secondary agent with a different personality&lt;/p&gt;

&lt;p&gt;Basic commands used during setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openclaw agents list
openclaw agents add nila
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once created, we configured bindings to map Slack accounts to specific agents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openclaw agents bind --agent main --bind slack:default
openclaw agents bind --agent nila --bind slack:nila
openclaw agents bindings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key behavior&lt;/p&gt;

&lt;p&gt;Bindings in OpenClaw are exclusive per target.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;slack:default → main agent&lt;/li&gt;
&lt;li&gt;slack:nila → nila agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A binding cannot be owned by multiple agents simultaneously.&lt;/p&gt;

&lt;p&gt;This design prevents routing conflicts and keeps conversation ownership clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Agent Routing Concept
&lt;/h2&gt;

&lt;p&gt;With the bindings configured, OpenClaw can route messages based on the Slack account interacting with the system.&lt;/p&gt;

&lt;p&gt;Example routing flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Slack (default account)
        ↓
   main agent

Slack (nila account)
        ↓
   nila agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach enables &lt;strong&gt;different agent personalities or capabilities within the same workspace&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Slack App Configuration
&lt;/h2&gt;

&lt;p&gt;During setup we encountered a common Slack DM issue:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sending messages to this app has been turned off.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In most cases, this is caused by Slack app configuration or installation state.&lt;/p&gt;

&lt;p&gt;To enable bot DM interactions correctly, the following settings are required.&lt;br&gt;
Required Slack App Settings&lt;/p&gt;

&lt;p&gt;✔ App Home messages enabled&lt;br&gt;
✔ Socket Mode enabled with a valid xapp- token&lt;br&gt;
✔ Required bot scopes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chat:write&lt;/li&gt;
&lt;li&gt;im:read&lt;/li&gt;
&lt;li&gt;im:history&lt;/li&gt;
&lt;li&gt;im:write&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After modifying scopes or permissions, always:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reinstall the Slack app&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Otherwise the new permissions will not take effect.&lt;/p&gt;
&lt;h2&gt;
  
  
  Debugging and Diagnostics
&lt;/h2&gt;

&lt;p&gt;OpenClaw provides useful commands for troubleshooting routing and connectivity issues.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw channels list
openclaw channels status &lt;span class="nt"&gt;--json&lt;/span&gt;
openclaw status
openclaw logs &lt;span class="nt"&gt;--follow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands help verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;channel bindings&lt;/li&gt;
&lt;li&gt;Slack connection status&lt;/li&gt;
&lt;li&gt;agent routing&lt;/li&gt;
&lt;li&gt;runtime logs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Important Behavior: Session Visibility
&lt;/h2&gt;

&lt;p&gt;One subtle behavior we noticed involves cross-session communication.&lt;/p&gt;

&lt;p&gt;If the policy&lt;br&gt;
&lt;code&gt;tools.sessions.visibility&lt;/code&gt;&lt;br&gt;
restricts visibility, then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agents may &lt;strong&gt;not be able to send messages across sessions&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is useful for enforcing &lt;strong&gt;isolation between agents&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;OpenClaw’s routing model makes it surprisingly easy to build multi-agent Slack assistants.&lt;/p&gt;

&lt;p&gt;With the right configuration, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run multiple agent personalities&lt;/li&gt;
&lt;li&gt;route conversations dynamically&lt;/li&gt;
&lt;li&gt;isolate sessions for security&lt;/li&gt;
&lt;li&gt;debug behavior through simple CLI tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture opens interesting possibilities for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI team assistants&lt;/li&gt;
&lt;li&gt;domain-specific agents&lt;/li&gt;
&lt;li&gt;developer copilots&lt;/li&gt;
&lt;li&gt;automated workflows&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
