<?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: Jamiu Tijani</title>
    <description>The latest articles on DEV Community by Jamiu Tijani (@jamiu__tijani).</description>
    <link>https://dev.to/jamiu__tijani</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%2F3016351%2F8b688110-eb83-4c39-88ee-35cf2f632575.png</url>
      <title>DEV Community: Jamiu Tijani</title>
      <link>https://dev.to/jamiu__tijani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jamiu__tijani"/>
    <language>en</language>
    <item>
      <title>I turned an Android phone into a Kubernetes worker node</title>
      <dc:creator>Jamiu Tijani</dc:creator>
      <pubDate>Tue, 09 Jun 2026 15:57:27 +0000</pubDate>
      <link>https://dev.to/jamiu__tijani/i-turned-an-android-phone-into-a-kubernetes-worker-node-4cc9</link>
      <guid>https://dev.to/jamiu__tijani/i-turned-an-android-phone-into-a-kubernetes-worker-node-4cc9</guid>
      <description>&lt;p&gt;A few months ago I had a thought: modern Android phones are carrying 8-core ARM SoCs, gigabytes of RAM, and fast storage sitting idle on a desk. What if a standard Kubernetes cluster could just... use them?&lt;/p&gt;

&lt;p&gt;That question became &lt;strong&gt;DroidNode&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get nodes
&lt;span class="go"&gt;NAME                        STATUS   ROLES    AGE
kali                        Ready    master   4d
&lt;/span&gt;&lt;span class="gp"&gt;droidnode-b96a49db497af1eb  Ready    &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;2h   ← Android phone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;standard &lt;code&gt;kubectl apply&lt;/code&gt; works and the pod runs on the phone.&lt;/p&gt;




&lt;h2&gt;
  
  
  The constraints that made it interesting
&lt;/h2&gt;

&lt;p&gt;The hardest constraint was &lt;strong&gt;no root&lt;/strong&gt;. Most container runtimes (Docker, containerd, even podman in its default mode) lean on kernel namespaces and cgroups and both requires elevated privileges on Android.&lt;/p&gt;

&lt;p&gt;The second constraint: &lt;strong&gt;no modifications to k3s or Kubernetes&lt;/strong&gt;. The control plane had to stay completely unaware that it was talking to an Android device. From the scheduler's perspective it needed to look like an ordinary Linux worker node.&lt;/p&gt;

&lt;p&gt;So the problem became: how do you run arbitrary Linux container workloads on Android, without root, while speaking fluent Kubernetes?&lt;/p&gt;




&lt;h2&gt;
  
  
  The key insight: proot
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://proot-me.github.io/" rel="noopener noreferrer"&gt;proot&lt;/a&gt; is a userspace implementation of &lt;code&gt;chroot&lt;/code&gt; built on &lt;code&gt;ptrace&lt;/code&gt;. Instead of asking the kernel to change the root filesystem (which requires root), proot intercepts every syscall the guest process makes and translates the paths in software.&lt;/p&gt;

&lt;p&gt;It's slower than a real namespace-based container runtime, but it works on Android with developer mode enabled.&lt;/p&gt;

&lt;p&gt;Basically the flow is :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f pod.yaml
    → k3s schedules pod to droidnode node
    → DroidNode agent receives pod spec
    → pulls OCI image layers from registry
    → unpacks layers into a rootfs directory
    → spawns: proot -r /path/to/rootfs -w /app /bin/sh ...
    → pod runs, logs stream back, status reported to k3s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Implementing the kubelet API
&lt;/h2&gt;

&lt;p&gt;Kubernetes doesn't care what's running the pods , it just talks HTTP to whatever is registered as the kubelet for a node. So I implemented the parts of the kubelet API that k3s actually uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /pods&lt;/code&gt; — return current pod list&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /containerLogs/{namespace}/{pod}/{container}&lt;/code&gt; — stream logs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /run/{namespace}/{pod}/{container}&lt;/code&gt; — exec (not yet implemented)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The node registers itself with k3s by creating a &lt;code&gt;Node&lt;/code&gt; object in the API server and then sending periodic heartbeat patches to the node's status. As long as the &lt;code&gt;Ready&lt;/code&gt; condition stays &lt;code&gt;True&lt;/code&gt; and &lt;code&gt;lastHeartbeatTime&lt;/code&gt; updates every 30 seconds, k3s treats it like any other node.&lt;/p&gt;

&lt;p&gt;Because k3s requires the kubelet endpoint to serve HTTPS with a certificate the control plane trusts. The agent generates its own CA on first run, writes it to disk, and you copy it to k3s once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adb shell run-as com.droidnode &lt;span class="nb"&gt;cat&lt;/span&gt; /data/data/com.droidnode/files/kubelet-ca.crt &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/android-kubelet-ca.crt
&lt;span class="nb"&gt;sudo cp&lt;/span&gt; /tmp/android-kubelet-ca.crt /etc/rancher/k3s/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, every restart reuses the same CA so the trust relationship persists.&lt;/p&gt;




&lt;h2&gt;
  
  
  OCI image pulling from scratch
&lt;/h2&gt;

&lt;p&gt;I couldn't use any existing container runtime library because they all assume Linux namespaces. So I wrote the OCI registry client from scratch in Rust.&lt;/p&gt;

&lt;p&gt;The flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch the image manifest from the registry (Docker Hub, GHCR, etc.)&lt;/li&gt;
&lt;li&gt;If it's a manifest list, pick the &lt;code&gt;linux/arm64&lt;/code&gt; platform entry&lt;/li&gt;
&lt;li&gt;Fetch each layer blob (gzipped tar)&lt;/li&gt;
&lt;li&gt;Unpack layers in order, applying whiteout files (deletions) as we go&lt;/li&gt;
&lt;li&gt;Write a sentinel file so we know the rootfs is ready next time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whiteout handling was surprisingly fiddly. OCI layers express file deletions as special &lt;code&gt;.wh.&lt;/code&gt; prefixed files (you have to process them in layer order or you end up with files that should have been deleted still present in the rootfs).&lt;/p&gt;

&lt;p&gt;Another notable issue is  hardlinks across layer boundaries. Android's internal storage filesystem doesn't support cross-directory hardlinks in some configurations, so I had to fall back to a copy when &lt;code&gt;link()&lt;/code&gt; fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;hard_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The architecture: The Standard
&lt;/h2&gt;

&lt;p&gt;The Rust agent follows &lt;a href="https://github.com/hassanhabib/The-Standard" rel="noopener noreferrer"&gt;Hassan Habib's The Standard&lt;/a&gt; strictly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Brokers → Foundation Services → Orchestration Services → Exposers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Brokers&lt;/strong&gt; wrap exactly one external system (OCI registry, filesystem, proot binary, k8s API). No logic, no conditionals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foundation services&lt;/strong&gt; each do one thing (pull an image, unpack a layer, run a workload).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration services&lt;/strong&gt; coordinate foundation services (reconciliation loop, image pipeline).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exposers&lt;/strong&gt; are thin entry points (the kubelet HTTPS server, the Android foreground service).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enforcing this made the codebase much easier to test in pieces — I could validate the OCI registry broker against Docker Hub independently, then layer the image pull service on top of it, and so on.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Android side: Kotlin foreground service
&lt;/h2&gt;

&lt;p&gt;On Android, a foreground service is the only reliable way to keep a process alive without root. The Kotlin layer is intentionally thin — it just:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starts the Rust agent as a native subprocess&lt;/li&gt;
&lt;li&gt;Holds a wake lock so Android doesn't kill it under memory pressure&lt;/li&gt;
&lt;li&gt;Monitors battery and network state&lt;/li&gt;
&lt;li&gt;Provides a debug UI (tap the notification to see live logs, node status, and pod events)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Rust agent writes to stdout; Kotlin tails it and feeds lines into a ring buffer that the debug UI reads. No JNI — clean process boundary.&lt;/p&gt;




&lt;h2&gt;
  
  
  What actually works today
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: v1
kind: Pod
metadata:
  name: hello-android
spec:
  nodeName: droidnode-&amp;lt;your-device-id&amp;gt;
  restartPolicy: Never
  containers:
    - name: hello
      image: alpine:latest
      command: ["/bin/sh", "-c"]
      args: ["echo hello from DroidNode; uname -m"]
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;kubectl logs hello-android
&lt;span class="c"&gt;# hello from DroidNode&lt;/span&gt;
&lt;span class="c"&gt;# aarch64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've tested with Alpine, Python HTTP servers, and &lt;code&gt;stefanprodan/podinfo&lt;/code&gt;. Images with a &lt;code&gt;WORKDIR&lt;/code&gt; set work correctly — the agent reads the &lt;code&gt;WorkingDir&lt;/code&gt; field from the image config and passes it to proot's &lt;code&gt;-w&lt;/code&gt; flag.&lt;/p&gt;




&lt;h2&gt;
  
  
  Known limitations
&lt;/h2&gt;

&lt;p&gt;This is a working proof of concept, not a production runtime. The main gaps:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Multi-container pods&lt;/td&gt;
&lt;td&gt;Only first container runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;restartPolicy: Always&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not implemented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volume mounts&lt;/td&gt;
&lt;td&gt;Source path mapping is broken&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network isolation&lt;/td&gt;
&lt;td&gt;Containers share host network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;kubectl exec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not implemented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load balancer pods (svclb)&lt;/td&gt;
&lt;td&gt;iptables fails inside proot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All of these are tracked as &lt;a href="https://github.com/c0d3g3n13/droidnode/issues" rel="noopener noreferrer"&gt;open issues&lt;/a&gt; if you want to pick one up.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;The most interesting unsolved problem is &lt;strong&gt;network isolation&lt;/strong&gt;. Right now every container shares the Android device's network interface. Implementing proper pod networking without root is genuinely hard, the closest viable approach is probably a userspace TCP proxy similar to what k3s does for services.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The repo is at &lt;a href="https://github.com/c0d3g3n13/droidnode" rel="noopener noreferrer"&gt;github.com/c0d3g3n13/droidnode&lt;/a&gt;. You need a device with developer mode enabled, an ARM64 Android phone (API 26+), and a k3s cluster to connect it to.&lt;/p&gt;

&lt;p&gt;If you find it interesting and want to contribute, the &lt;a href="https://github.com/c0d3g3n13/droidnode/issues" rel="noopener noreferrer"&gt;open issues&lt;/a&gt; are a good place to start. The architecture is strictly layered so most features can be added without touching much existing code.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>rust</category>
      <category>android</category>
      <category>opensource</category>
    </item>
    <item>
      <title>AATP: A Case Study in Designing a Protocol for Agentic AI Communication</title>
      <dc:creator>Jamiu Tijani</dc:creator>
      <pubDate>Fri, 04 Apr 2025 14:26:33 +0000</pubDate>
      <link>https://dev.to/jamiu__tijani/aatp-a-case-study-in-designing-a-protocol-for-agentic-ai-communication-2pnh</link>
      <guid>https://dev.to/jamiu__tijani/aatp-a-case-study-in-designing-a-protocol-for-agentic-ai-communication-2pnh</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;As I build the Agentic AI Transport Protocol (AATP), I’m exploring how agent-to-agent communication should work in a world of intelligent, autonomous systems. This is a preview of what’s coming—and why it matters.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🚧 Why I’m Building AATP
&lt;/h2&gt;

&lt;p&gt;Multi-agent systems are no longer theoretical—they’re becoming foundational to how modern AI applications are designed.&lt;/p&gt;

&lt;p&gt;In these ecosystems, agents aren’t just prompts or functions—they're &lt;strong&gt;collaborative entities&lt;/strong&gt; with roles, goals, and memory.&lt;/p&gt;

&lt;p&gt;But under the hood, their communication still relies on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generic REST APIs
&lt;/li&gt;
&lt;li&gt;WebSocket workarounds
&lt;/li&gt;
&lt;li&gt;Heavy message queues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these were designed for agents.&lt;/p&gt;

&lt;p&gt;I saw an opportunity to solve this with a dedicated, agent-focused protocol—something fast, browser-native, memory-aware, and purpose-built.&lt;/p&gt;

&lt;p&gt;That’s the origin of &lt;strong&gt;AATP&lt;/strong&gt;: the &lt;strong&gt;Agentic AI Transport Protocol&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 The Problem I’m Solving
&lt;/h2&gt;

&lt;p&gt;Even with frameworks like LangGraph or CrewAI, agent communication is &lt;strong&gt;loosely defined&lt;/strong&gt; and often &lt;strong&gt;hard-wired&lt;/strong&gt;. I needed something that offered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Structured, role-based messages
&lt;/li&gt;
&lt;li&gt;✅ Context passing without bloated prompts
&lt;/li&gt;
&lt;li&gt;✅ Compatibility with the browser and edge environments
&lt;/li&gt;
&lt;li&gt;✅ Clean hooks for memory and routing
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AATP is my answer to these needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 The Vision Behind AATP
&lt;/h2&gt;

&lt;p&gt;I'm designing AATP around four core ideas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intentful Messaging&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Agents should declare their goal, not just send data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory by Reference&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Instead of sending massive context, agents share memory keys or vector IDs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser-First&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No backend required—just a clean JS SDK that works out of the box.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Identity &amp;amp; Routing&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Agent URIs should be as meaningful as email addresses, like &lt;code&gt;agent://sales@aidra&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🧩 Planned AATP Packet Format
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"agent://planner@aidra"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"agent://writer@aidra"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"intent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"generate_outline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"conversation_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c987-42ef"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"memory_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qdrant://aidra/convo/c987"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Please create a 3-point summary based on our last discussion."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"planner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"router"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each field carries meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;intent&lt;/code&gt; gives purpose&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;memory_token&lt;/code&gt; provides continuity&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;trace&lt;/code&gt; helps with debugging and feedback loops&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Architecture (In Progress)
&lt;/h2&gt;

&lt;p&gt;Here’s the early sketch of what I’m building:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech (Planned)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transport&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTTP/2 + ProtoBuf or Cap’n Proto&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Client SDK&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TypeScript (browser) + Go (backend)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Qdrant / Pinecone / Redis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Routing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LangGraph or custom JS planner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HMAC, JWT, scoped agent permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It’s modular so developers can swap in their own memory systems, routers, or signing layers.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Prototyping and Testing So Far
&lt;/h2&gt;

&lt;p&gt;I’ve been testing AATP concepts using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LangGraph state injections&lt;/strong&gt; to simulate messages
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser-only agent demos&lt;/strong&gt; that route between roles
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory referencing with Qdrant&lt;/strong&gt; for persistent history
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Early Takeaways:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Embedding memory tokens is way more efficient than bloating prompts
&lt;/li&gt;
&lt;li&gt;Explicit &lt;code&gt;intent&lt;/code&gt; fields improve readability and routing logic
&lt;/li&gt;
&lt;li&gt;Client-side agents need a zero-config protocol to scale&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Where AATP Fits
&lt;/h2&gt;

&lt;p&gt;Even in its early stage, AATP could power projects I’m already working on, including:&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ AIDRA Platform
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multi-agent routing in the browser
&lt;/li&gt;
&lt;li&gt;Direct Lambda ↔ browser agent communication
&lt;/li&gt;
&lt;li&gt;Qdrant memory continuity with each exchange&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ Indexer Pipelines
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Trigger downstream agents like &lt;code&gt;agent://parser&lt;/code&gt; or &lt;code&gt;agent://validator&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Carry vector payloads for semantic traceability&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔐 What I’m Planning for Security
&lt;/h2&gt;

&lt;p&gt;I want AATP to be safe out of the box. Planned security features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role-based agent URIs
&lt;/li&gt;
&lt;li&gt;Signed messages (HMAC or JWT)
&lt;/li&gt;
&lt;li&gt;Namespace-based rate limits
&lt;/li&gt;
&lt;li&gt;Optional &lt;code&gt;auth.verify()&lt;/code&gt; middleware on both ends&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is &lt;strong&gt;traceable&lt;/strong&gt;, &lt;strong&gt;decentralized&lt;/strong&gt;, and &lt;strong&gt;secure&lt;/strong&gt; agent messaging.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 My Hope for AATP
&lt;/h2&gt;

&lt;p&gt;I’m not just trying to build a protocol—I’m trying to change the default for how agents interact.&lt;/p&gt;

&lt;h3&gt;
  
  
  If AATP succeeds:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Agents will &lt;strong&gt;communicate natively&lt;/strong&gt; without backend glue&lt;/li&gt;
&lt;li&gt;Memory and purpose will travel through every hop&lt;/li&gt;
&lt;li&gt;Agent-to-agent workflows will be &lt;strong&gt;as simple as emails&lt;/strong&gt;—but 10x faster&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📅 What’s Next
&lt;/h2&gt;

&lt;p&gt;In the coming months, I plan to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finalize the packet schema
&lt;/li&gt;
&lt;li&gt;Release the TypeScript SDK
&lt;/li&gt;
&lt;li&gt;Integrate AATP into a live AIDRA workflow
&lt;/li&gt;
&lt;li&gt;Open up an alpha version for early users&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Too often, agent communication is treated as an afterthought. But I believe it deserves a &lt;strong&gt;protocol of its own&lt;/strong&gt;—one that speaks the language of roles, memory, and purpose.&lt;/p&gt;

&lt;p&gt;AATP is still in the lab. But I’m confident it will become a foundational layer for the agentic future I’m helping build.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agents shouldn’t just speak to us—they should speak to each other.&lt;br&gt;&lt;br&gt;
AATP is how I’m making that possible.&lt;/p&gt;
&lt;/blockquote&gt;




</description>
    </item>
    <item>
      <title>Implementing LangGraph for Multi-Agent AI Systems</title>
      <dc:creator>Jamiu Tijani</dc:creator>
      <pubDate>Fri, 04 Apr 2025 14:07:03 +0000</pubDate>
      <link>https://dev.to/jamiu__tijani/implementing-langgraph-for-multi-agent-ai-systems-4fck</link>
      <guid>https://dev.to/jamiu__tijani/implementing-langgraph-for-multi-agent-ai-systems-4fck</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Learn how to orchestrate multiple AI agents in a coherent, collaborative system using &lt;strong&gt;LangGraph&lt;/strong&gt;, &lt;strong&gt;vector databases&lt;/strong&gt;, and thoughtful architectural patterns.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;The rise of agentic AI has opened the door to building intelligent, multi-agent systems that can &lt;strong&gt;reason, communicate, and collaborate&lt;/strong&gt; toward shared goals. But coordinating these agents effectively—while keeping memory, state, and context intact—is a different kind of challenge altogether.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;LangGraph&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;LangGraph offers a flexible, graph-based execution model for building &lt;strong&gt;multi-agent workflows&lt;/strong&gt; on top of powerful LLMs. It brings modularity, memory management, and dynamic control flow to the table—key ingredients for scaling agent architectures.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how to implement LangGraph in a production-grade, multi-agent system powered by &lt;strong&gt;OpenAI&lt;/strong&gt; models, &lt;strong&gt;vector databases&lt;/strong&gt;, and custom tool integrations.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Why Multi-Agent Systems?
&lt;/h2&gt;

&lt;p&gt;Traditional LLM applications are often &lt;strong&gt;single-agent&lt;/strong&gt; and synchronous—good for simple tasks, but limited when complexity rises.&lt;/p&gt;

&lt;p&gt;Multi-agent systems allow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Task specialization&lt;/strong&gt; (e.g., researcher vs coder vs tester agents)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel processing&lt;/strong&gt; of sub-tasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Negotiation and delegation&lt;/strong&gt; among agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic workflows&lt;/strong&gt; based on agent feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But... these benefits introduce new challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do agents &lt;strong&gt;communicate&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;How do you manage &lt;strong&gt;shared memory and state&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;How do you coordinate dynamic &lt;strong&gt;control flow&lt;/strong&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LangGraph solves exactly this.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What is LangGraph?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.langgraph.dev/" rel="noopener noreferrer"&gt;LangGraph&lt;/a&gt; is an open-source library that extends &lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt; by allowing you to define &lt;strong&gt;stateful agent workflows&lt;/strong&gt; using &lt;strong&gt;directed acyclic graphs (DAGs)&lt;/strong&gt; or &lt;strong&gt;finite state machines&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🔁 &lt;strong&gt;Loops and recursion&lt;/strong&gt; for iterative agent behavior&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;Agent messaging&lt;/strong&gt; support&lt;/li&gt;
&lt;li&gt;🧱 &lt;strong&gt;State abstraction&lt;/strong&gt; for long-running contexts&lt;/li&gt;
&lt;li&gt;🧠 Easy plug-in for &lt;strong&gt;vector stores&lt;/strong&gt;, memory, and tools&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Here’s what a typical LangGraph-powered multi-agent system looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐      ┌──────────────┐
│  User Input  ├─────▶│ Entry Agent  │
└──────────────┘      └────┬─────────┘
                           │
                   ┌──────▼──────┐
                   │  Router Agent│
                   └────┬───────▲┘
                        │       │
         ┌──────────────▼─┐ ┌───▼────────────┐
         │ Research Agent │ │ Codegen Agent  │
         └─────────────▲──┘ └──────▲─────────┘
                       │           │
                 ┌─────┴───────────▼─────┐
                 │  Evaluation Agent     │
                 └────────┬──────────────┘
                          ▼
                  ┌──────────────┐
                  │  Final Output│
                  └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each agent is implemented as a node in a LangGraph and can read/write to shared state.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Setting Up LangGraph
&lt;/h2&gt;

&lt;p&gt;Install the required dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;langgraph langchain openai qdrant-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optional (if you use tools or retrievers):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;beautifulsoup4 faiss-cpu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📦 Step 1: Define the Shared State
&lt;/h2&gt;

&lt;p&gt;LangGraph passes a shared &lt;code&gt;state&lt;/code&gt; dictionary to each node.&lt;/p&gt;

&lt;p&gt;Here’s an example schema:&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;state&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;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="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;# user input
&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;history&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="c1"&gt;# full agent interaction history
&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;documents&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="c1"&gt;# retrieved docs from vector store
&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&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="c1"&gt;# generated or modified code
&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluation&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="c1"&gt;# output from evaluator agent
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a dataclass or Pydantic model if you prefer strict typing.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤖 Step 2: Define Your Agents (Nodes)
&lt;/h2&gt;

&lt;p&gt;Each agent is a function that receives and returns the updated state.&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;researcher_agent&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;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;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;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vector_store&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="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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;docs&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;history&lt;/span&gt;&lt;span class="sh"&gt;"&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;Researcher retrieved docs.&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;state&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;coder_agent&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;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_prompt&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatCompletion&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;choices&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="n"&gt;message&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;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;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;code&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;history&lt;/span&gt;&lt;span class="sh"&gt;"&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;Coder generated code.&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;state&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔁 Step 3: Define Graph Flow
&lt;/h2&gt;

&lt;p&gt;LangGraph supports &lt;strong&gt;dynamic branching&lt;/strong&gt; based on conditions.&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="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;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;researcher&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;researcher_agent&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;coder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coder_agent&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;evaluator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;evaluator_agent&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;set_entry_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;researcher&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;researcher&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;coder&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;coder&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;evaluator&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;set_finish_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evaluator&lt;/span&gt;&lt;span class="sh"&gt;"&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;h2&gt;
  
  
  📚 Step 4: Integrate with Vector Stores
&lt;/h2&gt;

&lt;p&gt;LangGraph pairs well with vector databases like &lt;strong&gt;Qdrant&lt;/strong&gt;, &lt;strong&gt;Pinecone&lt;/strong&gt;, or &lt;strong&gt;Weaviate&lt;/strong&gt; for memory retrieval.&lt;/p&gt;

&lt;p&gt;Example Qdrant setup:&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;qdrant_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QdrantClient&lt;/span&gt;

&lt;span class="n"&gt;qdrant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;QdrantClient&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:6333&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;retriever&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdrant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_retriever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my_collection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;vector_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RetrieverWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retriever&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass documents between agents via shared state.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Step 5: Memory and Traceability
&lt;/h2&gt;

&lt;p&gt;To maintain &lt;strong&gt;persistent agent memory&lt;/strong&gt;, integrate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conversation history&lt;/strong&gt; into prompts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document memory&lt;/strong&gt; from vector search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intermediate state logging&lt;/strong&gt; (audit trail)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&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;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;history&lt;/span&gt;&lt;span class="sh"&gt;"&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;agent&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;Evaluator&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;action&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;Scored output at 9/10&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;For observability, consider emitting events to a queue or logging system.&lt;/p&gt;




&lt;h2&gt;
  
  
  💡 Advanced: Branching and Feedback Loops
&lt;/h2&gt;

&lt;p&gt;LangGraph supports conditional logic like:&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;decision_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="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bug&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&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;evaluation&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# loop back to codegen
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final_output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Loop until success!&lt;/p&gt;




&lt;h2&gt;
  
  
  🔒 Security and Guardrails
&lt;/h2&gt;

&lt;p&gt;For production-grade systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;function-calling&lt;/strong&gt; or &lt;strong&gt;tool-calling&lt;/strong&gt; for safe agent actions&lt;/li&gt;
&lt;li&gt;Validate user inputs and prompt outputs&lt;/li&gt;
&lt;li&gt;Add &lt;strong&gt;rate limits&lt;/strong&gt; and timeout handling&lt;/li&gt;
&lt;li&gt;Monitor &lt;strong&gt;token usage&lt;/strong&gt; and cost alerts&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧪 Testing the System
&lt;/h2&gt;

&lt;p&gt;LangGraph can be easily tested with mock agents:&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;mock_agent&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;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;history&lt;/span&gt;&lt;span class="sh"&gt;"&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;Mock agent called&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;state&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can simulate flows with &lt;code&gt;app.invoke()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;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;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;Build a weather app&lt;/span&gt;&lt;span class="sh"&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;code&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;
  
  
  🧠 Real-World Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customer Support AI&lt;/strong&gt;: Router agent + Knowledge retriever + Response generator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Research Assistant&lt;/strong&gt;: Planner agent + Web scraper + Summarizer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Review Bot&lt;/strong&gt;: Linter agent + Fixer agent + Unit test generator&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 LangGraph vs Traditional Pipelines
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;LangGraph&lt;/th&gt;
&lt;th&gt;Traditional Chain&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Multiple agents&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;🚫 Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branching logic&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;🚫 Hard-coded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared state&lt;/td&gt;
&lt;td&gt;✅ Explicit&lt;/td&gt;
&lt;td&gt;❌ Implicit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debuggability&lt;/td&gt;
&lt;td&gt;✅ High&lt;/td&gt;
&lt;td&gt;⚠️ Difficult&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Looping support&lt;/td&gt;
&lt;td&gt;✅ Native&lt;/td&gt;
&lt;td&gt;🚫 Hacky&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;LangGraph provides a clean, scalable, and debuggable way to coordinate multiple AI agents with shared context and dynamic flow control. When paired with a robust vector database and tool integrations, it unlocks a new generation of &lt;strong&gt;cooperative, intelligent systems&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Start small. Model your agent flows. Think in graphs, not just chains.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📚 Further Reading &amp;amp; Tools
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.langgraph.dev/" rel="noopener noreferrer"&gt;LangGraph Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qdrant.tech/" rel="noopener noreferrer"&gt;Qdrant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://platform.openai.com/docs/guides/function-calling" rel="noopener noreferrer"&gt;OpenAI Function Calling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Multi-agent_system" rel="noopener noreferrer"&gt;Multi-Agent Systems (Wikipedia)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




</description>
    </item>
  </channel>
</rss>
