<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Architecture on Yarang's Tech Lair</title><link>https://blog.agentthread.dev/tags/architecture/</link><description>Recent content in Architecture on Yarang's Tech Lair</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 28 Jun 2026 09:00:35 +0900</lastBuildDate><atom:link href="https://blog.agentthread.dev/tags/architecture/index.xml" rel="self" type="application/rss+xml"/><item><title>MCP Integration Guide: Integrating Discord MCP with ZeroClaw Runtime</title><link>https://blog.agentthread.dev/post/mcp-integration-guide-integrating-discord-mcp-with-zeroclaw-runtime/</link><pubDate>Sun, 28 Jun 2026 09:00:35 +0900</pubDate><guid>https://blog.agentthread.dev/post/mcp-integration-guide-integrating-discord-mcp-with-zeroclaw-runtime/</guid><description>&lt;p&gt;With the recent release of &lt;strong&gt;ZeroClaw&lt;/strong&gt;, a high-performance Rust agent runtime, we&amp;rsquo;ve been deeply contemplating ways to maximize the efficiency of multi-agent systems. In particular, the complexity of communication protocols encountered during the design of the [Discord Decision MCP] architecture was a decisive factor in adopting MCP (Model Context Protocol) as a standard interface.&lt;/p&gt;
&lt;p&gt;In this post, we will explain how to actually integrate &lt;strong&gt;Discord MCP&lt;/strong&gt; within the ZeroClaw environment, detailing the process of agents receiving and processing Discord messages with concrete code examples.&lt;/p&gt;
&lt;h3 id="1-architecture-design-dual-communication-on-a-single-channel"&gt;1. Architecture Design: Dual Communication on a Single Channel
&lt;/h3&gt;&lt;p&gt;In the previous [Discord MCP] Gateway architecture, the gateway played the role of filtering events and delivering them to agents. However, by directly implementing the MCP client within ZeroClaw, we&amp;rsquo;ve altered the design to eliminate the intermediate layer and reduce latency.&lt;/p&gt;
&lt;p&gt;The core idea is a flow where the &lt;strong&gt;&lt;code&gt;MCP Client&lt;/code&gt;&lt;/strong&gt; transmits Discord events to the ZeroClaw process via &lt;code&gt;stdio&lt;/code&gt;, and then sends the agent&amp;rsquo;s responses back to Discord.&lt;/p&gt;
&lt;h3 id="2-essential-dependencies-and-setup-rust"&gt;2. Essential Dependencies and Setup (Rust)
&lt;/h3&gt;&lt;p&gt;As ZeroClaw is written in Rust, it utilizes the asynchronous runtime &lt;code&gt;tokio&lt;/code&gt; for high concurrency processing and &lt;code&gt;serde&lt;/code&gt; for JSON handling. Communication with the MCP server is assumed to involve exchanging JSON-RPC messages via standard input/output (stdio).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Cargo.toml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;async-trait&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-mcp-client-implementation"&gt;3. MCP Client Implementation
&lt;/h3&gt;&lt;p&gt;We define a simple client structure to control the Discord MCP server within ZeroClaw. This client uses the &lt;code&gt;tools/call&lt;/code&gt; method, which adheres to the MCP standard, to execute Discord bot functionalities.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::process::{Command, Stdio};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::io::{BufReader, BufWriter, Write};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DiscordMCPClient&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; DiscordMCPClient {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;() -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self { id: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/// Executes an MCP tool to send a message to a Discord channel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send_message&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self, channel_id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, content: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.id &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Execute MCP server process (e.g., Python-based Discord MCP server)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; child &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Command::new(&lt;span style="color:#e6db74"&gt;&amp;#34;python3&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .arg(&lt;span style="color:#e6db74"&gt;&amp;#34;discord_mcp_server.py&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .stdin(Stdio::piped())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .stdout(Stdio::piped())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .spawn()&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; stdin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; child.stdin.as_mut().ok(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to open stdin&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; stdout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BufReader::new(child.stdout.as_mut().ok(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to open stdout&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; request &lt;span style="color:#f92672"&gt;=&lt;/span&gt; MCPRequest {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;self&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method: &lt;span style="color:#e6db74"&gt;&amp;#34;tools/call&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;send_message&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;arguments&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;channel_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;channel_id&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Send request
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; request_json &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;request)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;writeln!&lt;/span&gt;(stdin, &lt;span style="color:#e6db74"&gt;&amp;#34;{}&amp;#34;&lt;/span&gt;, request_json)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// (In a real implementation, logic to parse the response from an asynchronous reader is needed)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Omitted here for simplicity.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-integration-with-zeroclaw-agents"&gt;4. Integration with ZeroClaw Agents
&lt;/h3&gt;&lt;p&gt;Now, let&amp;rsquo;s use the &lt;code&gt;DiscordMCPClient&lt;/code&gt; created above within ZeroClaw&amp;rsquo;s agent loop. This scenario demonstrates an agent notifying Discord upon completing a specific task.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ZeroClawAgent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; discord_client: &lt;span style="color:#a6e22e"&gt;DiscordMCPClient&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; ZeroClawAgent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run_task&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self, task: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Agent] Starting task: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, task);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Complex reasoning or file processing logic (omitted)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Task &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; completed.&amp;#34;&lt;/span&gt;, task);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Send result to Discord
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; self.discord_client.send_message(&lt;span style="color:#e6db74"&gt;&amp;#34;123456789&amp;#34;&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;result).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Agent] Successfully sent Discord notification&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Agent] Sending failed: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; agent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ZeroClawAgent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; discord_client: &lt;span style="color:#a6e22e"&gt;DiscordMCPClient&lt;/span&gt;::new(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent.run_task(&lt;span style="color:#e6db74"&gt;&amp;#34;Analyze server logs&amp;#34;&lt;/span&gt;).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-efficiency-and-security-considerations-architecture-insights"&gt;5. Efficiency and Security Considerations (Architecture Insights)
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Resource Management&lt;/strong&gt;: Similar to the trending &amp;lsquo;Adrafinil&amp;rsquo; on [Hacker News], applying &lt;code&gt;speculative decoding&lt;/code&gt; by disconnecting the Discord MCP connection when the agent is idle and only establishing it when a task is active can save resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: As highlighted in issues related to [Anonymous GitHub accounts], parameters passed to the MCP server (e.g., API tokens) should be managed via environment variables or fetched from a separate secure storage (Vault). Hardcoding secrets in code is critical.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: As discussed in communication platform design considerations, it&amp;rsquo;s important to include retry logic in the MCP client, taking into account Discord API&amp;rsquo;s Rate Limits.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="conclusion"&gt;Conclusion
&lt;/h3&gt;&lt;p&gt;Integrating ZeroClaw and Discord MCP goes beyond simply creating a bot; it&amp;rsquo;s a process of building a &lt;strong&gt;standardized interface&lt;/strong&gt; for agents to interact with the external world. Leveraging our experience in building [MCP] blog automation systems, we plan to further develop more sophisticated multi-agent collaboration systems.&lt;/p&gt;</description></item><item><title>ZeroClaw Agent Runtime: Implementing a TCP/IP Architecture for High-Performance Multi-Agent Communication</title><link>https://blog.agentthread.dev/post/zeroclaw-agent-runtime-implementing-a-tcp/ip-architecture-for-high-performance-multi-agent-communication/</link><pubDate>Fri, 26 Jun 2026 09:01:09 +0900</pubDate><guid>https://blog.agentthread.dev/post/zeroclaw-agent-runtime-implementing-a-tcp/ip-architecture-for-high-performance-multi-agent-communication/</guid><description>&lt;p&gt;Hello! As the open-source AI and agent ecosystem rapidly expands, there&amp;rsquo;s a growing interest in &amp;ldquo;multi-agent systems&amp;rdquo; where multiple agents collaborate beyond a single LLM. In a previous post, we covered the architectural design of the ZeroClaw project. This time, we aim to introduce the specific implementation details of how the actual ZeroClaw runtime internally handles inter-agent communication and achieves high performance by leveraging Rust&amp;rsquo;s powerful asynchronous runtime.&lt;/p&gt;
&lt;h2 id="challenges-with-existing-communication-and-zeroclaws-approach"&gt;Challenges with Existing Communication and ZeroClaw&amp;rsquo;s Approach
&lt;/h2&gt;&lt;p&gt;Typical MCP (Model Context Protocol) or basic agent systems primarily handle communication through in-memory sharing within a single process or simple local function calls. However, as systems become more complex and agents become distributed, the following problems arise:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Scalability Limitations:&lt;/strong&gt; Single-process memory buffers are finite, and bottlenecks occur when hundreds of agents send and receive messages simultaneously.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Increased Coupling:&lt;/strong&gt; Communication between agents is tightly coupled with logic, making it difficult to replace or update specific agents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network Separation:&lt;/strong&gt; If the communication methods differ between local development environments and cloud deployment environments, code modifications are required.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To address these issues, ZeroClaw adopts a hybrid approach that combines &lt;strong&gt;&amp;ldquo;file-based architecture design&amp;rdquo;&lt;/strong&gt; with a &lt;strong&gt;&amp;ldquo;TCP/IP networking layer.&amp;rdquo;&lt;/strong&gt; Agents declaratively record their state in the file system, and actual message transmission is handled via asynchronous TCP sockets.&lt;/p&gt;
&lt;h2 id="asynchronous-server-structure-using-rust-tokio"&gt;Asynchronous Server Structure Using Rust Tokio
&lt;/h2&gt;&lt;p&gt;The core of ZeroClaw is its high-performance networking layer built on Rust&amp;rsquo;s &lt;code&gt;tokio&lt;/code&gt; runtime. Each agent runs as an independent task, and messages are exchanged safely through channels.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a simplified example of the message broker, which is central to the ZeroClaw runtime.&lt;/p&gt;
&lt;h3 id="1-defining-basic-message-structures"&gt;1. Defining Basic Message Structures
&lt;/h3&gt;&lt;p&gt;First, we define the data structures for messages exchanged between agents. &lt;code&gt;serde&lt;/code&gt; is used to automate serialization.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::collections::HashMap;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; source: String, &lt;span style="color:#75715e"&gt;// Sender agent ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; target: String, &lt;span style="color:#75715e"&gt;// Receiver agent ID (or &amp;#34;broadcast&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; payload: &lt;span style="color:#a6e22e"&gt;PayloadType&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;PayloadType&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Text(String),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Data(HashMap&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;), &lt;span style="color:#75715e"&gt;// Map for flexible data transfer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Control(ControlSignal),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ControlSignal&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Start,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Stop,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; HeartBeat,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-implementing-asynchronous-tcp-handlers"&gt;2. Implementing Asynchronous TCP Handlers
&lt;/h3&gt;&lt;p&gt;Actual communication occurs through &lt;code&gt;tokio::net::TcpListener&lt;/code&gt;. Each connection is handled as a separate task, so the slow response of one agent does not bring down the entire system.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::net::{TcpListener, TcpStream};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::io::{AsyncReadExt, AsyncWriteExt};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::mpsc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Clone)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentConfig&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run_agent_server&lt;/span&gt;(config: &lt;span style="color:#a6e22e"&gt;AgentConfig&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; listener &lt;span style="color:#f92672"&gt;=&lt;/span&gt; TcpListener::bind(&lt;span style="color:#e6db74"&gt;&amp;#34;127.0.0.1:8080&amp;#34;&lt;/span&gt;).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent Server listening on 127.0.0.1:8080&amp;#34;&lt;/span&gt;, config.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Channel for message routing (a more complex router would be used in actual implementation)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; (tx, &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Receiving task (spawned)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; config_clone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; config.clone();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok((&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; socket, addr)) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; listener.accept().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Connection from &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, config_clone.id, addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; tx_clone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.clone();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; buf &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#ae81ff"&gt;1024&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; socket.read(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; buf).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(n) &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; n &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Connection closed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(n) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; n,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to read from socket; err = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Message parsing (simplified logic)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; received_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;buf[&lt;span style="color:#f92672"&gt;..&lt;/span&gt;n];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Deserialization would be performed here in reality
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, String::from_utf8_lossy(received_data));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ... (Business logic processing) ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Example sending task (periodic heartbeat)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; interval &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::time::interval(tokio::time::Duration::from_secs(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interval.tick().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; hb &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source: &lt;span style="color:#a6e22e"&gt;config&lt;/span&gt;.id.clone(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target: &lt;span style="color:#e6db74"&gt;&amp;#34;broadcast&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload: &lt;span style="color:#a6e22e"&gt;PayloadType&lt;/span&gt;::Control(ControlSignal::HeartBeat),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Would actually write to a socket or send externally
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Sending Heartbeat...&amp;#34;&lt;/span&gt;, config.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code demonstrates the basic framework for a ZeroClaw agent to asynchronously receive requests from other agents and periodically report its status. Since each connection is executed independently via &lt;code&gt;tokio::spawn&lt;/code&gt;, thousands of concurrent connections can be handled efficiently.&lt;/p&gt;
&lt;h2 id="team-agent-communication-and-protocol-design"&gt;Team Agent Communication and Protocol Design
&lt;/h2&gt;&lt;p&gt;Beyond simple 1:1 communication, ZeroClaw aims for &lt;strong&gt;team-level communication&lt;/strong&gt;. This connects with the previously discussed &amp;ldquo;Team Agent Communication Architecture.&amp;rdquo;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pub/Sub Pattern:&lt;/strong&gt; Messages are delivered in bulk to a group of agents subscribed to a specific topic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Peer-to-Peer (P2P):&lt;/strong&gt; Minimizes latency by enabling direct communication between agents without going through a central server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ZeroClaw&amp;rsquo;s protocol is encapsulated and transmitted over the TCP layer using JSON or binary formats (like MessagePack for performance-critical scenarios). This forms a Network Abstraction Layer, allowing higher-level business logic to be written without worrying whether communication is local or remote.&lt;/p&gt;
&lt;h2 id="conclusion-towards-scalable-agent-systems"&gt;Conclusion: Towards Scalable Agent Systems
&lt;/h2&gt;&lt;p&gt;ZeroClaw is being designed as a true distributed system, going beyond a simple LLM wrapper. By combining Rust&amp;rsquo;s memory safety and zero-cost abstractions with &lt;code&gt;tokio&lt;/code&gt;&amp;rsquo;s powerful asynchronous processing capabilities, we are building a stable and fast agent runtime.&lt;/p&gt;
&lt;p&gt;In the next post, we will debug the flow of how an LLM makes decisions and performs actual actions through MCP tools on top of this communication architecture.&lt;/p&gt;
&lt;h2 id="reference-code-and-resources"&gt;Reference Code and Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;ZeroClaw GitHub Repository (preparing for open-source)&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.elsevier.com/books/the-garbage-collection-handbook/jones/978-0-12-812720-5" target="_blank" rel="noopener"
 &gt;The Garbage Collection Handbook: The Art of Automatic Memory Management (2nd Ed)&lt;/a&gt; - A classic and authoritative text on memory management, recently mentioned in the news.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you for reading!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Designing MCP Authentication Architecture for Zero-Touch OAuth Implementation</title><link>https://blog.agentthread.dev/post/designing-mcp-authentication-architecture-for-zero-touch-oauth-implementation/</link><pubDate>Fri, 19 Jun 2026 09:00:58 +0900</pubDate><guid>https://blog.agentthread.dev/post/designing-mcp-authentication-architecture-for-zero-touch-oauth-implementation/</guid><description>&lt;p&gt;Recently, I encountered an interesting technological trend called &amp;lsquo;Zero-Touch OAuth for MCP&amp;rsquo;. During the integration of MCP (Model Context Protocol) with our &lt;code&gt;ZeroClaw&lt;/code&gt; runtime and &lt;code&gt;blog-api-server&lt;/code&gt; that we are developing, ensuring security without compromising user experience is an essential task. In this post, we will design a &amp;lsquo;Zero-Touch&amp;rsquo; authentication flow that helps users connect to MCP clients without any complex separate configurations, and explore how to implement it in actual code.&lt;/p&gt;
&lt;h3 id="why-zero-touch"&gt;Why Zero-Touch?
&lt;/h3&gt;&lt;p&gt;Traditional OAuth 2.0 flows often require users to obtain a &amp;lsquo;Client ID&amp;rsquo; and &amp;lsquo;Client Secret&amp;rsquo; and enter them into a configuration file. However, for general users or developers, this presents a significant barrier to entry. Zero-Touch OAuth aims for a flow where the client automatically attempts authentication through pre-registered metadata, and users simply need to click an &amp;lsquo;Allow&amp;rsquo; button.&lt;/p&gt;
&lt;h3 id="architecture-design"&gt;Architecture Design
&lt;/h3&gt;&lt;p&gt;We will configure &lt;code&gt;blog-api-server&lt;/code&gt; as the MCP Provider and &lt;code&gt;Claude Code&lt;/code&gt; or custom clients as MCP Consumers. The core idea is to build a Public Client environment that does not store Secrets by using the &lt;strong&gt;PKCE (Proof Key for Code Exchange)&lt;/strong&gt; extension.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Core Components:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;MCP Client (Consumer)&lt;/strong&gt;: An agent running in the user&amp;rsquo;s local environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth Server&lt;/strong&gt;: The OAuth2 authentication server implemented within &lt;code&gt;blog-api-server&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource Server&lt;/strong&gt;: The actual blog API.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="implementation-step-1-server-side-blog-api-server"&gt;Implementation Step 1: Server Side (blog-api-server)
&lt;/h3&gt;&lt;p&gt;First, we need to add a simple authentication endpoint to the Rust-based &lt;code&gt;blog-api-server&lt;/code&gt;. We will extend the architecture mentioned in the previous post, &lt;em&gt;&amp;rsquo;[blog-api-server] Adding Language Parameter to MCP Blog Client&amp;rsquo;&lt;/em&gt;, to make the Auth module independent.&lt;/p&gt;
&lt;p&gt;Here, we will show the core logic: the &lt;strong&gt;Verification&lt;/strong&gt; logic. This is the process of verifying the &lt;code&gt;code_verifier&lt;/code&gt; received from the client.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// blog-api-server/src/auth/handler.rs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; axum::{extract::State, Json};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; sha2::{Digest, Sha256};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; base64::Engine &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; _;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TokenRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; code: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; code_verifier: String, &lt;span style="color:#75715e"&gt;// Random string generated by the client via PKCE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; redirect_uri: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Serialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TokenResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; access_token: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; token_type: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; expires_in: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;exchange_token&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; State(state): &lt;span style="color:#a6e22e"&gt;State&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AppState&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Json(payload): &lt;span style="color:#a6e22e"&gt;Json&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;TokenRequest&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Json&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;TokenResponse&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Retrieve Authorization Code from DB
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; auth_record &lt;span style="color:#f92672"&gt;=&lt;/span&gt; state.db.get_auth_code(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;payload.code)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .map_err(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;_&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Invalid code&amp;#34;&lt;/span&gt;.to_string())&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. PKCE Challenge Verification (Core Security Logic)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; hasher &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Sha256::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hasher.update(payload.code_verifier.as_bytes());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; hashed_verifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hasher.finalize();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; encoded_verifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; base64::engine::general_purpose::&lt;span style="color:#66d9ef"&gt;URL_SAFE_NO_PAD&lt;/span&gt;.encode(hashed_verifier);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; encoded_verifier &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; auth_record.code_challenge {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Code verifier mismatch&amp;#34;&lt;/span&gt;.to_string());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. Issue Access Token
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; access_token &lt;span style="color:#f92672"&gt;=&lt;/span&gt; generate_jwt(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;state.secrets, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;auth_record.user_id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(Json(TokenResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; access_token,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; token_type: &lt;span style="color:#e6db74"&gt;&amp;#34;Bearer&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; expires_in: &lt;span style="color:#ae81ff"&gt;3600&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code hashes the &lt;code&gt;code_verifier&lt;/code&gt; sent by the client and checks if it matches the &lt;code&gt;code_challenge&lt;/code&gt; generated when the initial authentication request was sent. This process is the core that makes &amp;lsquo;Zero-Touch&amp;rsquo; secure.&lt;/p&gt;
&lt;h3 id="implementation-step-2-client-side-mcp-client"&gt;Implementation Step 2: Client Side (MCP Client)
&lt;/h3&gt;&lt;p&gt;Now, the client can obtain a token without user intervention (or with minimal intervention). Let&amp;rsquo;s write an example MCP client using Python.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; hashlib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; base64
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; requests
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; urllib.parse &lt;span style="color:#f92672"&gt;import&lt;/span&gt; urlencode
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; os &lt;span style="color:#75715e"&gt;# Import os module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Zero-Touch Configuration (Hardcoded or Environment Variables)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CLIENT_ID &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;zeroclaw-mcp-client&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AUTH_URL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://api.myblog.com/oauth/authorize&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TOKEN_URL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://api.myblog.com/oauth/token&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;REDIRECT_URI &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;http://localhost:3000/callback&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Generate PKCE Code Verifier&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;random_bytes &lt;span style="color:#f92672"&gt;=&lt;/span&gt; os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urandom(&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;code_verifier &lt;span style="color:#f92672"&gt;=&lt;/span&gt; base64&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urlsafe_b64encode(random_bytes)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rstrip(&lt;span style="color:#e6db74"&gt;b&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;=&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;decode(&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Generate Code Challenge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;challenge_digest &lt;span style="color:#f92672"&gt;=&lt;/span&gt; hashlib&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sha256(code_verifier&lt;span style="color:#f92672"&gt;.&lt;/span&gt;encode(&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;))&lt;span style="color:#f92672"&gt;.&lt;/span&gt;digest()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;code_challenge &lt;span style="color:#f92672"&gt;=&lt;/span&gt; base64&lt;span style="color:#f92672"&gt;.&lt;/span&gt;urlsafe_b64encode(challenge_digest)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;rstrip(&lt;span style="color:#e6db74"&gt;b&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;=&amp;#39;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;decode(&lt;span style="color:#e6db74"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_auth_url&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;response_type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;client_id&amp;#34;&lt;/span&gt;: CLIENT_ID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;redirect_uri&amp;#34;&lt;/span&gt;: REDIRECT_URI,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;scope&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;mcp:read mcp:write&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;code_challenge&amp;#34;&lt;/span&gt;: code_challenge,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;code_challenge_method&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;S256&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;AUTH_URL&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;?&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;urlencode(params)&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;exchange_code_for_token&lt;/span&gt;(auth_code):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;grant_type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;authorization_code&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: auth_code,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;redirect_uri&amp;#34;&lt;/span&gt;: REDIRECT_URI,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;client_id&amp;#34;&lt;/span&gt;: CLIENT_ID,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;code_verifier&amp;#34;&lt;/span&gt;: code_verifier &lt;span style="color:#75715e"&gt;# Sent to the server for verification&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; requests&lt;span style="color:#f92672"&gt;.&lt;/span&gt;post(TOKEN_URL, data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; response&lt;span style="color:#f92672"&gt;.&lt;/span&gt;json()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Usage Example&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1. User authenticates in the browser via get_auth_url() (first time)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 2. Extract &amp;#39;code&amp;#39; from the redirected query parameters&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 3. token = exchange_code_for_token(code)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="considerations-for-zeroclaw-runtime-integration"&gt;Considerations for ZeroClaw Runtime Integration
&lt;/h3&gt;&lt;p&gt;As mentioned in our previous retrospective, &lt;em&gt;&amp;rsquo;[ZeroClaw] Q1 2026 Development Direction Meeting Minutes&amp;rsquo;&lt;/em&gt;, our agent runtime must prioritize security and scalability. If we integrate the OAuth flow implemented above into ZeroClaw&amp;rsquo;s &lt;code&gt;Multi-Agent&lt;/code&gt; architecture, each agent can have an independent identity.&lt;/p&gt;
&lt;p&gt;In particular, as discussed in &lt;em&gt;&amp;rsquo;[ZeroClaw] Multi-Agent Communication Protocol Design&amp;rsquo;&lt;/em&gt;, this Access Token can be used to securely access resources (APIs) of other agents during inter-agent communication, laying the foundation for secure access. This goes beyond simple blog automation and marks the first step towards a distributed system where agents trust and delegate tasks to each other.&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion
&lt;/h3&gt;&lt;p&gt;Zero-Touch OAuth is an excellent approach that achieves both user convenience and security. We plan to start with small projects like &lt;code&gt;blog-api-server&lt;/code&gt; and gradually evolve it into a core authentication module for &lt;code&gt;ZeroClaw&lt;/code&gt;. The code above provides a basic framework, and for actual operational environments, logic such as state verification and refresh token rotation should be added.&lt;/p&gt;
&lt;p&gt;In the next post, we will debug the &amp;lsquo;Handshake&amp;rsquo; process of actually exchanging data with the MCP server using the tokens secured in this way.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Stop Using JWTs: The Practicality and Implementation of Session-Based Authentication</title><link>https://blog.agentthread.dev/post/stop-using-jwts-the-practicality-and-implementation-of-session-based-authentication/</link><pubDate>Wed, 17 Jun 2026 09:00:39 +0900</pubDate><guid>https://blog.agentthread.dev/post/stop-using-jwts-the-practicality-and-implementation-of-session-based-authentication/</guid><description>&lt;h1 id="stop-using-jwts-the-practicality-and-implementation-of-session-based-authentication"&gt;Stop Using JWTs: The Practicality and Implementation of Session-Based Authentication
&lt;/h1&gt;&lt;p&gt;Recently, the topic &amp;ldquo;Stop Using JWTs&amp;rdquo; has resurfaced as a hot potato in communities like Hacker News. When JWTs (JSON Web Tokens) first emerged, they were considered the standard for Microservice Architectures (MSA) thanks to the magic word &amp;ldquo;stateless.&amp;rdquo; However, in the reality of operating web services, we often fall into the trap of statelessness.&lt;/p&gt;
&lt;p&gt;This article will explore why many developers are abandoning JWTs and returning to traditional session-based authentication (or database-based tokens), and how to implement it in practice.&lt;/p&gt;
&lt;h2 id="the-sweet-trap-of-jwts"&gt;The Sweet Trap of JWTs
&lt;/h2&gt;&lt;p&gt;The biggest advantage of JWTs is that they don&amp;rsquo;t require storing user state on the server. Since all information is contained within the token itself, only the signature needs to be verified without a database lookup. Theoretically, this offers excellent scalability.&lt;/p&gt;
&lt;p&gt;However, this &amp;ldquo;advantage&amp;rdquo; quickly becomes a &amp;ldquo;disadvantage.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="1-revocation-problem"&gt;1. Revocation Problem
&lt;/h3&gt;&lt;p&gt;Once issued, JWTs are valid until their expiration date. What if a user logs out, or an administrator needs to force them to log out?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Option 1:&lt;/strong&gt; Let the token remain valid until it expires, as it cannot be immediately revoked. (Impossible as a safety measure)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Option 2:&lt;/strong&gt; Introduce a blacklist. (Ultimately requires a DB/Redis lookup -&amp;gt; loss of stateless advantage)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The moment you introduce a blacklist, you need to check it for every JWT verification, thus losing the advantage of &amp;ldquo;without database lookup.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="2-token-size-and-overhead"&gt;2. Token Size and Overhead
&lt;/h3&gt;&lt;p&gt;JWTs, including headers, payloads, and signatures, are significantly larger than typical session IDs. The more claims (Roles, permissions, etc.) you include per user, the larger the token becomes. This wastes network bandwidth with every request.&lt;/p&gt;
&lt;h2 id="returning-to-session-based-authentication"&gt;Returning to Session-Based Authentication
&lt;/h2&gt;&lt;p&gt;In conclusion, it&amp;rsquo;s better to accept the fact that &lt;strong&gt;&amp;ldquo;state is managed on the server-side.&amp;rdquo;&lt;/strong&gt; Using an in-memory database like Redis allows for very fast session management, and immediate logout or forced logout is possible.&lt;/p&gt;
&lt;p&gt;In this section, we will build a simple yet robust session-based authentication system using Go and Redis.&lt;/p&gt;
&lt;h3 id="prerequisites"&gt;Prerequisites
&lt;/h3&gt;&lt;p&gt;We assume Redis is installed and running locally.&lt;/p&gt;
&lt;h3 id="implementation-code-go"&gt;Implementation Code (Go)
&lt;/h3&gt;&lt;p&gt;The following code is a simple HTTP server that provides &lt;code&gt;/login&lt;/code&gt;, &lt;code&gt;/protected&lt;/code&gt;, and &lt;code&gt;/logout&lt;/code&gt; endpoints.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;encoding/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;github.com/go-redis/redis/v8&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;github.com/google/uuid&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;github.com/gorilla/mux&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;golang.org/x/crypto/bcrypt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;context&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Background&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rdb&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;redis&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// User information (in a real application, this would be fetched from a DB)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;userDB&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;map&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#e6db74"&gt;&amp;#34;user1&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;$2a$14$ajq8Q7fbnFR0nXf8bA7HcuiJ/6V.Z.yzX1lYh8g8h5x6z7x8x9x0x&amp;#34;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// password: &amp;#34;password&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Credentials&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Username&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;username&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;Password&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`json:&amp;#34;password&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Initialize Redis client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;rdb&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;redis&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewClient&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;redis&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Options&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Addr&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;localhost:6379&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Password&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// no password set&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;DB&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// use default DB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mux&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewRouter&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;HandleFunc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/login&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;loginHandler&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;Methods&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;HandleFunc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/protected&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;authMiddleware&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;protectedHandler&lt;/span&gt;)).&lt;span style="color:#a6e22e"&gt;Methods&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;HandleFunc&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/logout&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;authMiddleware&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;logoutHandler&lt;/span&gt;)).&lt;span style="color:#a6e22e"&gt;Methods&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Println&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Server starting on port 8000...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Fatal&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ListenAndServe&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;:8000&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Login handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;loginHandler&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ResponseWriter&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;creds&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Credentials&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;json&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewDecoder&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Body&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;Decode&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;creds&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusBadRequest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Check if user exists and verify password&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;hashedPassword&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;userDB&lt;/span&gt;[&lt;span style="color:#a6e22e"&gt;creds&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Username&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; !&lt;span style="color:#a6e22e"&gt;exists&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusUnauthorized&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bcrypt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;CompareHashAndPassword&lt;/span&gt;([]byte(&lt;span style="color:#a6e22e"&gt;hashedPassword&lt;/span&gt;), []byte(&lt;span style="color:#a6e22e"&gt;creds&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Password&lt;/span&gt;)); &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusUnauthorized&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Generate a new session ID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;sessionToken&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;uuid&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewString&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Store session in Redis (expires in 24 hours)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;rdb&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Set&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;sessionToken&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;creds&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Username&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hour&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;Err&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Set cookie (HttpOnly, Secure recommended)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;SetCookie&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Cookie&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;session_token&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;sessionToken&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Expires&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Now&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;Add&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hour&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;HttpOnly&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Secure&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Only in HTTPS environment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Path&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;SameSite&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;SameSiteStrictMode&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusOK&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;json&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewEncoder&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;Encode&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;map&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Login successful&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Authentication middleware&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;authMiddleware&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;HandlerFunc&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;HandlerFunc&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ResponseWriter&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Cookie&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;session_token&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ErrNoCookie&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusUnauthorized&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusBadRequest&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;sessionToken&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;// Retrieve session from Redis&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;response&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rdb&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Get&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;sessionToken&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;Result&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;redis&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusUnauthorized&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusInternalServerError&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;// Optionally, store username in request context&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#75715e"&gt;// r = r.WithContext(context.WithValue(r.Context(), &amp;#34;username&amp;#34;, response))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;next&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Protected resource handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;protectedHandler&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ResponseWriter&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Cookie&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;session_token&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;username&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rdb&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Get&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;Result&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;json&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewEncoder&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;Encode&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;map&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;fmt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Sprintf&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello %s, you accessed a protected route!&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;username&lt;/span&gt;)})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Logout handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;logoutHandler&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ResponseWriter&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;r&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Cookie&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;session_token&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;sessionToken&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Delete session from Redis (immediate revocation)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;rdb&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Del&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;ctx&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;sessionToken&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Invalidate cookie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;SetCookie&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Cookie&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;session_token&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Expires&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Now&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;Add&lt;/span&gt;(&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Hour&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;HttpOnly&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;Path&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;WriteHeader&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;http&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;StatusOK&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;json&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewEncoder&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;Encode&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;map&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Logout successful&amp;#34;&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="code-explanation-and-application-tips"&gt;Code Explanation and Application Tips
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Secure Cookie Usage:&lt;/strong&gt; &lt;code&gt;HttpOnly&lt;/code&gt; and &lt;code&gt;Secure&lt;/code&gt; flags are used to prevent XSS (Cross-Site Scripting) and Man-in-the-Middle attacks. It is safer to encourage the client (browser) to store tokens in cookies rather than LocalStorage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Leveraging Redis:&lt;/strong&gt; Redis, being single-threaded, offers fast atomic operations and is ideal for use as a session store. Even if Redis goes down, the data isn&amp;rsquo;t permanently needed (as users can re-login), so it&amp;rsquo;s configured for fast response times.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Immediate Logout:&lt;/strong&gt; The &lt;code&gt;logoutHandler&lt;/code&gt; includes code to delete the key from Redis (&lt;code&gt;rdb.Del&lt;/code&gt;). This perfectly solves JWT&amp;rsquo;s biggest weakness: &amp;ldquo;inability to log out.&amp;rdquo; The moment the key is deleted, that token (session ID) is no longer valid.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion-what-should-you-choose"&gt;Conclusion: What Should You Choose?
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;When JWTs are good:&lt;/strong&gt; When the system you are building consists of truly &lt;strong&gt;independent microservices&lt;/strong&gt;, user authentication is needed for inter-service communication, and logout/reissue logic is not critical for simple API communications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;When Sessions/Cookies are good:&lt;/strong&gt; For general web services, SaaS, and most cases where user security (immediate action required for account termination) is important.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The phrase &amp;ldquo;Stop Using JWTs&amp;rdquo; is not because JWT is a bad technology, but because it is &lt;strong&gt;misused and applied inappropriately for the situation.&lt;/strong&gt; Adding complex JWT libraries and blacklist logic to a problem that can be solved with a simple session store can be an act of accumulating technical debt.&lt;/p&gt;
&lt;p&gt;We recommend applying the Go code example above to your project and experiencing the ease of management and security firsthand.&lt;/p&gt;</description></item><item><title>Building a High-Performance Agent Runtime with Rust: An In-depth Analysis of the ZeroClaw Architecture</title><link>https://blog.agentthread.dev/post/building-a-high-performance-agent-runtime-with-rust-an-in-depth-analysis-of-the-zeroclaw-architecture/</link><pubDate>Tue, 16 Jun 2026 09:00:39 +0900</pubDate><guid>https://blog.agentthread.dev/post/building-a-high-performance-agent-runtime-with-rust-an-in-depth-analysis-of-the-zeroclaw-architecture/</guid><description>&lt;h1 id="building-a-high-performance-agent-runtime-with-rust-an-in-depth-analysis-of-the-zeroclaw-architecture"&gt;Building a High-Performance Agent Runtime with Rust: An In-depth Analysis of the ZeroClaw Architecture
&lt;/h1&gt;&lt;p&gt;Recently, we designed and discussed the future direction of a high-performance Rust-based agent runtime through the &lt;strong&gt;ZeroClaw&lt;/strong&gt; project. Moving beyond the limitations of existing Python-based LLM applications or single-server architectures, building a multi-agent system by leveraging Rust&amp;rsquo;s inherent safety and excellent parallelism has been a technically challenging endeavor. In this article, we will explore ZeroClaw&amp;rsquo;s core architectural design, communication protocols, and the specific characteristics of Rust that need consideration during actual implementation.&lt;/p&gt;
&lt;h2 id="1-why-rust-safe-concurrency"&gt;1. Why Rust? (Safe Concurrency)
&lt;/h2&gt;&lt;p&gt;The core of a multi-agent system is concurrency. Numerous agents must run simultaneously, communicating with each other and sharing states. Python&amp;rsquo;s GIL (Global Interpreter Lock) hinders true parallel processing, and Go&amp;rsquo;s (Goroutine) garbage collection (GC) can sometimes lead to unpredictable latency. In contrast, &lt;strong&gt;Rust offers &amp;lsquo;Zero-cost Abstraction&amp;rsquo; and &amp;lsquo;Fearless Concurrency&amp;rsquo;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the ZeroClaw project, message passing between agents is implemented using &lt;code&gt;tokio::sync::mpsc&lt;/code&gt; channels, enabling lock-free asynchronous communication. This allows for maximum CPU resource utilization while completely eliminating data races at compile time.&lt;/p&gt;
&lt;h2 id="2-communication-protocol-design-file-based-vs-memory-based"&gt;2. Communication Protocol Design: File-Based vs. Memory-Based
&lt;/h2&gt;&lt;p&gt;The most debated aspect during the architectural design phase was the &amp;lsquo;method of communication between agents&amp;rsquo;. Initially, we considered a &lt;strong&gt;[Multi-Agent] file-based architecture design&lt;/strong&gt;. This approach, treating the file system as shared memory, offered the advantages of easy implementation and straightforward debugging. However, for ZeroClaw, which aims for a high-performance runtime, I/O bottlenecks were a critical concern.&lt;/p&gt;
&lt;p&gt;Consequently, we adopted a &lt;strong&gt;memory-based event bus architecture.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="21-implementing-the-request-response-pattern"&gt;2.1. Implementing the Request-Response Pattern
&lt;/h3&gt;&lt;p&gt;Since simple fire-and-forget was insufficient and task delegation between agents was necessary, we had to implement a Request-Response pattern. For this, we actively utilized Rust&amp;rsquo;s type system.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::{mpsc, oneshot};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::collections::HashMap;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Define messages to be exchanged between agents
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskRequest { id: String, payload: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskResponse { id: String, result: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Agent actor struct
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentActor&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Map of senders to send messages to other agents
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; peers: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, mpsc::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; AgentActor {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;(id: String, receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receiver,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; peers: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;::new(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Register a peer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;register_peer&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self, id: String, sender: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.peers.insert(id, sender);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Execute message loop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent started&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.receiver.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; msg {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentMessage::TaskRequest { id, payload } &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received Task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, id, payload);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Perform actual task (LLM call, etc.)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processed &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; by &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, payload, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// (In actual implementation, logic to send a response back to the requester is needed)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _ &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code provides a minimal skeleton for ZeroClaw&amp;rsquo;s communication layer. Each agent runs as an independent task (&lt;code&gt;tokio::spawn&lt;/code&gt;) and exchanges messages through channels.&lt;/p&gt;
&lt;h2 id="3-integration-with-mcp-the-bridge-pattern"&gt;3. Integration with MCP: The Bridge Pattern
&lt;/h2&gt;&lt;p&gt;As discussed in the &lt;strong&gt;[Discord Decision MCP]&lt;/strong&gt; architectural design document, the agent runtime needs to communicate with the external world. We adopted MCP (Model Context Protocol) as a standard interface, designing it so that agents within ZeroClaw can interact with platforms like Discord or blog APIs.&lt;/p&gt;
&lt;p&gt;A crucial point here is &lt;strong&gt;bridging the gap between Rust&amp;rsquo;s powerful type system and external JSON-based protocols.&lt;/strong&gt; We leverage &lt;code&gt;serde_json&lt;/code&gt; to deserialize MCP messages into internal structs and pass them between agents while maintaining type safety.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Struct for calling MCP tools
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPToolCall&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tool_name: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; arguments: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, serde_json::Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Example logic for handling an MCP call detected by an agent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_mcp_message&lt;/span&gt;(msg: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;MCPToolCall, Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; call: &lt;span style="color:#a6e22e"&gt;MCPToolCall&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str(msg)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Type verification is completed internally within Rust
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(call)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-roadmap-for-h1-2026-directions-for-advancement"&gt;4. Roadmap for H1 2026: Directions for Advancement
&lt;/h2&gt;&lt;p&gt;As mentioned in the &lt;strong&gt;[ZeroClaw] H1 2026 Development Direction Meeting Minutes&lt;/strong&gt;, we are focusing on optimization beyond simple implementation.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Agent Scaling:&lt;/strong&gt; Currently, agents are created with static configurations. We plan to introduce auto-scaling logic that dynamically increases and decreases agent instances using &lt;code&gt;tokio::task::spawn&lt;/code&gt; based on load.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Back-pressure Handling:&lt;/strong&gt; To prevent channels from overflowing when the processing speed is faster than LLM API call rates, we need to meticulously adjust the buffer strategies of &lt;code&gt;tokio::sync::mpsc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observability:&lt;/strong&gt; Moving beyond simple logging, we need to build a structure that allows for distributed tracing of message flows between agents using the &lt;code&gt;tracing&lt;/code&gt; crate.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;ZeroClaw is not just another agent framework. It aims to be an infrastructure for operating large-scale LLM applications, built on Rust&amp;rsquo;s safety and performance. The insights gained from analyzing the codebase architecture are focused on &amp;lsquo;how to manage complexity&amp;rsquo;, which clarifies our future development direction. For any developer requiring a high-performance runtime, ZeroClaw will be a powerful option.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Designing and Implementing a Communication Protocol for MCP-based Multi-Agent Systems in Rust</title><link>https://blog.agentthread.dev/post/designing-and-implementing-a-communication-protocol-for-mcp-based-multi-agent-systems-in-rust/</link><pubDate>Mon, 15 Jun 2026 09:00:53 +0900</pubDate><guid>https://blog.agentthread.dev/post/designing-and-implementing-a-communication-protocol-for-mcp-based-multi-agent-systems-in-rust/</guid><description>&lt;p&gt;Recently, while working on the &amp;lsquo;ZeroClaw&amp;rsquo; project and MCP (Model Context Protocol), I&amp;rsquo;ve keenly felt the necessity of a &lt;strong&gt;Multi-Agent System&lt;/strong&gt; that goes beyond a single agent. To build a structure where agents can exchange meaningful data and collaborate, rather than simply sending prompts to an LLM, a robust &lt;strong&gt;Communication Protocol&lt;/strong&gt; is essential.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;rsquo;ll explore the design process for multi-agent communication based on the MCP architecture and how to implement it on ZeroClaw (Rust), a high-performance runtime.&lt;/p&gt;
&lt;h3 id="1-problem-definition-why-a-communication-protocol"&gt;1. Problem Definition: Why a Communication Protocol?
&lt;/h3&gt;&lt;p&gt;In previous implementations like [blog-api-server] or [Discord MCP], the &amp;lsquo;Request-Response&amp;rsquo; structure was primarily followed. This involved a unidirectional flow where the client sent a request, and the server processed and responded. However, in a multi-agent environment, this structure alone is insufficient for the following reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Asynchrony:&lt;/strong&gt; If Agent A delegates a task to Agent B and Agent A stops execution until B completes, the overall system throughput decreases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Event-Driven Interaction:&lt;/strong&gt; Some agents need to monitor system state changes (e.g., file creation, log updates) and signal other agents under specific conditions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reliability:&lt;/strong&gt; Messages must not be lost in situations of network instability or temporary agent failures.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="2-protocol-design-request-task-completion"&gt;2. Protocol Design: Request, Task, Completion
&lt;/h3&gt;&lt;p&gt;To address these issues, we designed a &lt;strong&gt;Task-Based Messaging Protocol&lt;/strong&gt;. This protocol extends the MCP standard message format and consists of three main message types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TaskRequest:&lt;/strong&gt; Initiates a task. Used when Agent A delegates a specific task to Agent B.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TaskUpdate:&lt;/strong&gt; Reports progress. Conveys intermediate results for long-running tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TaskResult:&lt;/strong&gt; Final outcome. Returns data along with a success or failure status.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-implementing-the-zeroclaw-communication-layer-in-rust"&gt;3. Implementing the ZeroClaw Communication Layer in Rust
&lt;/h3&gt;&lt;p&gt;ZeroClaw implements this protocol in a type-safe manner using Rust&amp;rsquo;s powerful type system and its asynchronous runtime (Tokio). Below is a simplified message definition and handler structure.&lt;/p&gt;
&lt;h4 id="31-message-definition-based-on-json-rpc"&gt;3.1. Message Definition (Based on JSON-RPC)
&lt;/h4&gt;&lt;p&gt;MCP is fundamentally based on JSON-RPC 2.0, and we adhere to this standard while including the metadata necessary for inter-agent communication.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// src/protocol/message.rs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; uuid::Uuid;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: String, &lt;span style="color:#75715e"&gt;// Unique message ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; sender: String, &lt;span style="color:#75715e"&gt;// Sender agent ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; target: String, &lt;span style="color:#75715e"&gt;// Recipient agent ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; timestamp: &lt;span style="color:#66d9ef"&gt;i64&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Timestamp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; payload: &lt;span style="color:#a6e22e"&gt;Payload&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Actual data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[serde(tag = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Payload&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#[serde(rename = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;task/request&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskRequest {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_id: &lt;span style="color:#a6e22e"&gt;Uuid&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; description: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#[serde(rename = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;task/result&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskResult {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_id: &lt;span style="color:#a6e22e"&gt;Uuid&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status: &lt;span style="color:#a6e22e"&gt;TaskStatus&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; data: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#[serde(rename = &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;system/ping&amp;#34;&lt;/span&gt;&lt;span style="color:#75715e"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SystemPing,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TaskStatus&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Success,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Failure(String), &lt;span style="color:#75715e"&gt;// Reason for failure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Pending,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="32-agent-runtime-structure"&gt;3.2. Agent Runtime Structure
&lt;/h4&gt;&lt;p&gt;In ZeroClaw, each agent runs as an independent Tokio task. Inter-agent communication occurs through channels, and a Mediator routes these messages.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// src/runtime/agent.rs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::mpsc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;crate&lt;/span&gt;::protocol::message::{AgentMessage, Payload};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Agent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Sender for outgoing messages
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Receiver for incoming messages
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; Agent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;(id: String) -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; (tx, rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self { id, tx, rx }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// The agent&amp;#39;s main execution loop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent started&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.rx.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.handle_message(msg).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Error handling message: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_message&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, msg: &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; msg.payload {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Payload::SystemPing &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Logic to respond to ping with pong
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// In a real environment, this would use the client&amp;#39;s tx to send a response
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received Ping from &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, msg.sender);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Payload::TaskRequest { task_id, description, context } &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received Task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, task_id, description);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// LLM calls or tool execution logic would go here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Example: Result return logic (simulated)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// self.send_result(task_id, ...).await;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _ &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received unhandled message type&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-conclusion-and-next-steps"&gt;4. Conclusion and Next Steps
&lt;/h3&gt;&lt;p&gt;Through the structured communication layer described above, we achieve an architecture capable of &lt;strong&gt;task-unit collaboration&lt;/strong&gt;, moving beyond simple text generation. The &amp;lsquo;high-performance agent runtime&amp;rsquo; goal for the [ZeroClaw] project in the first half of 2026 will be realized by integrating LLM inference logic on this solid foundation.&lt;/p&gt;
&lt;p&gt;The next post will delve into the implementation details of a &amp;lsquo;Planner&amp;rsquo; agent that uses tools by calling an LLM over this communication protocol.&lt;/p&gt;
&lt;h3 id="references"&gt;References
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;[ZeroClaw] Multi-Agent Architecture Design Proposal&lt;/li&gt;
&lt;li&gt;[Claude Code] Team Agent Communication Architecture&lt;/li&gt;
&lt;li&gt;Rust Tokio Documentation&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>[ZeroClaw] Rust Channel-Based IPC Design for Asynchronous Agent Runtime</title><link>https://blog.agentthread.dev/post/zeroclaw-rust-channel-based-ipc-design-for-asynchronous-agent-runtime/</link><pubDate>Thu, 11 Jun 2026 09:00:42 +0900</pubDate><guid>https://blog.agentthread.dev/post/zeroclaw-rust-channel-based-ipc-design-for-asynchronous-agent-runtime/</guid><description>&lt;h1 id="zeroclaw-rust-channel-based-ipc-design-for-asynchronous-agent-runtime"&gt;[ZeroClaw] Rust Channel-Based IPC Design for Asynchronous Agent Runtime
&lt;/h1&gt;&lt;p&gt;Hello. Recently, while enhancing the &amp;lsquo;Multi-Agent Architecture&amp;rsquo;, the core of the &lt;strong&gt;ZeroClaw&lt;/strong&gt; project, I would like to share my experience building a &lt;strong&gt;high-performance asynchronous communication (IPC, Inter-Process Communication)&lt;/strong&gt; environment that goes beyond simple message passing.&lt;/p&gt;
&lt;p&gt;The previous synchronous communication method increased coupling between agents and became a bottleneck (Single Point of Failure) that could halt the entire system due to the failure of one agent. To address this, we designed an event-driven, loosely coupled architecture using Rust&amp;rsquo;s powerful concurrency feature, the &lt;strong&gt;&lt;code&gt;tokio&lt;/code&gt; runtime&lt;/strong&gt;, and &lt;strong&gt;MPSC (Multi-Producer, Single-Consumer) channels&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In this post, we will examine how channels were designed and implemented to maximize the efficiency of the agent runtime, along with actual code.&lt;/p&gt;
&lt;h2 id="1-problems-with-the-existing-architecture-and-the-need-for-asynchronous-design"&gt;1. Problems with the Existing Architecture and the Need for Asynchronous Design
&lt;/h2&gt;&lt;p&gt;Until now, ZeroClaw agents primarily used the &lt;strong&gt;synchronous RPC&lt;/strong&gt; pattern, requesting messages and waiting for responses. However, as the number of agents increased to dozens and they began performing complex tasks (e.g., analyzing file-based architectures, processing large-scale logs), the following problems arose:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Blocking Issue:&lt;/strong&gt; While Agent A waits for a response from Agent B, Agent A cannot perform other tasks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex Error Propagation:&lt;/strong&gt; When a specific agent crashed or timed out, it was complicated to propagate the error to agents higher up the call chain.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To solve this, we adopted an asynchronous pattern: &lt;strong&gt;&amp;ldquo;An agent sends a message and immediately performs other tasks. The processed result is received as an event.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="2-event-loop-structure-using-rusts-tokiosyncmpsc"&gt;2. Event Loop Structure Using Rust&amp;rsquo;s &lt;code&gt;tokio::sync::mpsc&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;The MPSC channel provided by Rust&amp;rsquo;s &lt;code&gt;tokio&lt;/code&gt; crate ensures high throughput and low latency, making it ideal for agent runtimes. Each agent has its own &lt;strong&gt;Task (unit of work)&lt;/strong&gt;, which executes independently via &lt;code&gt;tokio::spawn&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="core-design-points"&gt;Core Design Points
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Message Bus:&lt;/strong&gt; Each agent holds a sender (&lt;code&gt;tx&lt;/code&gt;) and a receiver (&lt;code&gt;rx&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Event Loop:&lt;/strong&gt; The receiver (&lt;code&gt;rx&lt;/code&gt;) runs in an infinite loop (&lt;code&gt;loop&lt;/code&gt;), asynchronously waiting (&lt;code&gt;recv()&lt;/code&gt;) until a message arrives.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-practical-code-a-concrete-implementation-example"&gt;3. Practical Code: A Concrete Implementation Example
&lt;/h2&gt;&lt;p&gt;Now, let&amp;rsquo;s write code that demonstrates how agents communicate within the ZeroClaw runtime.&lt;/p&gt;
&lt;h3 id="step-1-define-the-message-protocol"&gt;Step 1: Define the Message Protocol
&lt;/h3&gt;&lt;p&gt;First, we need to define the data structures that will be exchanged between agents. It is recommended to use an &lt;code&gt;Enum&lt;/code&gt; to manage message types safely.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Cargo.toml dependencies
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// [dependencies]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// tokio = { version = &amp;#34;1&amp;#34;, features = [&amp;#34;full&amp;#34;] }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// serde = { version = &amp;#34;1&amp;#34;, features = [&amp;#34;derive&amp;#34;] }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::mpsc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Serialize, Deserialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskAssigned { task_id: String, description: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskCompleted { task_id: String, result: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StatusCheck,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="step-2-implement-agent-struct-and-runner"&gt;Step 2: Implement Agent Struct and Runner
&lt;/h3&gt;&lt;p&gt;Each agent has a unique ID and a receiver (&lt;code&gt;rx&lt;/code&gt;). The &lt;code&gt;run&lt;/code&gt; method is the core function that manages the agent&amp;rsquo;s lifecycle.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Agent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; Agent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;(id: String, rx: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self { id, rx }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent started. Listening for messages...&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Asynchronously wait for message reception
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.rx.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; msg {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentMessage::TaskAssigned { task_id, description } &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Received task: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; - &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, task_id, description);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Actual logic processing (e.g., file analysis, external API calls)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Here, for example, we assume it takes 1 second and then sends a completion message.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentMessage::StatusCheck &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Status: Active&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _ &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent shutting down.&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="step-3-main-runtime-and-channel-connection"&gt;Step 3: Main Runtime and Channel Connection
&lt;/h3&gt;&lt;p&gt;In the main function, we create multiple agents, connect the channels, and then execute them in parallel using &lt;code&gt;tokio::spawn&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Create channel (capacity 32)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; (tx, rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Create and run agent (separated into asynchronous tasks)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; agent_handle &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; agent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Agent::new(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent-A&amp;#34;&lt;/span&gt;.to_string(), rx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent.run().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. Send messages from the main runtime
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Other agents or API servers can use this tx to send messages.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Assign task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.send(AgentMessage::TaskAssigned {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_id: &lt;span style="color:#e6db74"&gt;&amp;#34;T-101&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; description: &lt;span style="color:#e6db74"&gt;&amp;#34;Analyze server logs&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Check status
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.send(AgentMessage::StatusCheck).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 4. Wait for the agent to complete its task (in a real environment, it would continue running)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; drop(tx); &lt;span style="color:#75715e"&gt;// Sender drops -&amp;gt; channel closes -&amp;gt; agent loop termination condition met
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent_handle.&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-zeroclaw-project-application-effects"&gt;4. ZeroClaw Project Application Effects
&lt;/h2&gt;&lt;p&gt;As a result of applying the structure above to the ZeroClaw runtime, we achieved the following benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Improved Parallel Processing Performance:&lt;/strong&gt; Since agents run within their own &lt;code&gt;tokio&lt;/code&gt; tasks, we were able to efficiently utilize CPU cores.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced Coupling:&lt;/strong&gt; The main logic doesn&amp;rsquo;t need to know the internal implementation of a specific agent; it simply calls &lt;code&gt;tx.send&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graceful Shutdown:&lt;/strong&gt; By dropping &lt;code&gt;tx&lt;/code&gt;, the channel closes, and the agent detects that no more messages will arrive, naturally exiting the &lt;code&gt;while let&lt;/code&gt; loop and shutting down.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Rust&amp;rsquo;s ownership system and &lt;code&gt;tokio&lt;/code&gt;&amp;rsquo;s asynchronous abstractions become powerful weapons in building multi-agent systems. In the next post, we will cover how these agents persist state when combined with a &lt;strong&gt;file-based architecture&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The development of ZeroClaw&amp;rsquo;s high-performance agent runtime continues.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Building a Lightweight MCP Server with Rust and ZeroClaw: An Efficient Agent Communication Structure</title><link>https://blog.agentthread.dev/post/building-a-lightweight-mcp-server-with-rust-and-zeroclaw-an-efficient-agent-communication-structure/</link><pubDate>Wed, 10 Jun 2026 09:00:57 +0900</pubDate><guid>https://blog.agentthread.dev/post/building-a-lightweight-mcp-server-with-rust-and-zeroclaw-an-efficient-agent-communication-structure/</guid><description>&lt;h1 id="building-a-lightweight-mcp-server-with-rust-and-zeroclaw-an-efficient-agent-communication-structure"&gt;Building a Lightweight MCP Server with Rust and ZeroClaw: An Efficient Agent Communication Structure
&lt;/h1&gt;&lt;p&gt;As evident in the recent article &amp;ldquo;Grit: Rewriting Git in Rust with Agents,&amp;rdquo; the Rust language is being re-evaluated for its value as a runtime for agent systems. Our team&amp;rsquo;s &lt;code&gt;ZeroClaw&lt;/code&gt; runtime is also under development with high performance and safety as its goals, and with this in mind, we are increasingly focusing on how to efficiently build an MCP (Model Context Protocol) server.&lt;/p&gt;
&lt;p&gt;Instead of traditional heavy Python-based servers or complex Node.js architectures, we propose a lightweight MCP server structure that leverages Rust&amp;rsquo;s concurrency and low-latency capabilities. In this article, we will write a Rust-based MCP server example that can be immediately applied in practice, while capitalizing on the advantages of the &lt;code&gt;ZeroClaw&lt;/code&gt; architecture.&lt;/p&gt;
&lt;h2 id="1-combining-zeroclaw-architecture-and-mcp"&gt;1. Combining ZeroClaw Architecture and MCP
&lt;/h2&gt;&lt;p&gt;The core of the &lt;code&gt;ZeroClaw&lt;/code&gt; project lies in its file-based architectural design and the efficient implementation of its multi-agent communication protocol. The most crucial aspects when building an MCP server are &lt;strong&gt;reducing the overhead of data serialization/deserialization (Serde)&lt;/strong&gt; and &lt;strong&gt;asynchronous request handling&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;By utilizing Rust&amp;rsquo;s &lt;code&gt;tokio&lt;/code&gt; runtime and &lt;code&gt;serde_json&lt;/code&gt;, we can handle JSON-based MCP protocols with an overhead in the nanosecond range. This is a critical element, especially for large-scale log processing or monitoring systems (as experienced with &lt;code&gt;[blog-api-server]&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="2-core-structure-asynchronous-request-routing"&gt;2. Core Structure: Asynchronous Request Routing
&lt;/h2&gt;&lt;p&gt;We will build the skeleton of an MCP server using only the standard library and a few essential crates, without complex dependencies. This structure follows &lt;code&gt;ZeroClaw&lt;/code&gt;&amp;rsquo;s agent-to-agent communication pattern and ensures safety in a multi-threaded environment, not just a single-threaded one.&lt;/p&gt;
&lt;h3 id="21-cargotoml-configuration"&gt;2.1. Cargo.toml Configuration
&lt;/h3&gt;&lt;p&gt;First, add project dependencies.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;hyper&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.14&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="22-defining-mcp-message-structure"&gt;2.2. Defining MCP Message Structure
&lt;/h3&gt;&lt;p&gt;MCP fundamentally has a structure similar to JSON-RPC. We actively utilize Rust&amp;rsquo;s type system to ensure data integrity during agent-to-agent communication.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// src/types.rs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; jsonrpc: String, &lt;span style="color:#75715e"&gt;// Always &amp;#34;2.0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; method: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; params: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; result: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; error: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;MCPError&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPError&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; code: &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; message: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3-implementing-a-lightweight-request-handler"&gt;3. Implementing a Lightweight Request Handler
&lt;/h2&gt;&lt;p&gt;In line with &lt;code&gt;ZeroClaw&lt;/code&gt;&amp;rsquo;s philosophy, we will remove unnecessary abstraction layers and write intuitive handlers. The following code demonstrates the flow of parsing incoming requests, performing appropriate processing based on the method name, and returning a response.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// src/main.rs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; hyper::{Body, Request, Response, Server, StatusCode};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; hyper::service::{make_service_fn, service_fn};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::convert::Infallible;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; types::{MCPRequest, MCPResponse};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_mcp_request&lt;/span&gt;(req: &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; req.method.as_str() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/list&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Example of returning a list of tools
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(serde_json::&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;get_weather&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Get current weather&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;calculate&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Perform math operations&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/call&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Actual tool execution logic (calling ZeroClaw Agent, etc.)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Parameter validation logic goes here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent executing with params: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, req.params);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(serde_json::&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({&lt;span style="color:#e6db74"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;})),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _ &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: Some(types::MCPError {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; code: &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32601&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message: &lt;span style="color:#e6db74"&gt;&amp;#34;Method not found&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http_handler&lt;/span&gt;(req: &lt;span style="color:#a6e22e"&gt;Request&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Body&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Response&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Body&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, Infallible&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; whole_body &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; hyper::body::to_bytes(req.into_body()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(bytes) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; bytes,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Error reading body: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Ok(Response::builder()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .status(StatusCode::&lt;span style="color:#66d9ef"&gt;INTERNAL_SERVER_ERROR&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .body(Body::from(&lt;span style="color:#e6db74"&gt;&amp;#34;Internal Server Error&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .unwrap());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// JSON Parsing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; mcp_req: &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; serde_json::from_slice(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;whole_body) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(req) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; req,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Ok(Response::builder()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .status(StatusCode::&lt;span style="color:#66d9ef"&gt;BAD_REQUEST&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .body(Body::from(&lt;span style="color:#e6db74"&gt;&amp;#34;Invalid JSON&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .unwrap());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// MCP Logic Processing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; mcp_res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; handle_mcp_request(mcp_req).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Response Conversion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; json_body &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;mcp_res) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(json) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; json,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;{}&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(Response::new(Body::from(json_body)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; make_svc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; make_service_fn(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;_conn&lt;span style="color:#f92672"&gt;|&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; { Ok::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;_, Infallible&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(service_fn(http_handler)) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; addr &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ([&lt;span style="color:#ae81ff"&gt;127&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;], &lt;span style="color:#ae81ff"&gt;3000&lt;/span&gt;).into();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; server &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Server::bind(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;addr).serve(make_svc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;MCP Server listening on http://&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; server.&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Server error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-advanced-optimization-zeroclaw-integration"&gt;4. Advanced Optimization: ZeroClaw Integration
&lt;/h2&gt;&lt;p&gt;The code above is a basic HTTP server. To unleash the true power of &lt;code&gt;ZeroClaw&lt;/code&gt;, this server needs to be integrated as a task within the agent runtime.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Channel-based Communication&lt;/strong&gt;: Instead of directly handling HTTP requests, send requests through a &lt;code&gt;tokio::sync::mpsc&lt;/code&gt; channel to the internal agent queue. This aligns with &lt;code&gt;ZeroClaw&lt;/code&gt;&amp;rsquo;s asynchronous message passing structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stealable Work Queue&lt;/strong&gt;: Implement a work queue to allow agents to efficiently distribute tasks in a multi-core environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="5-conclusion"&gt;5. Conclusion
&lt;/h2&gt;&lt;p&gt;By writing an MCP server in Rust, you can fully leverage the benefits of high-performance runtimes like &lt;code&gt;ZeroClaw&lt;/code&gt;. The key is not just changing the language, but designing an architecture that minimizes overhead in agent-to-agent communication. We encourage you to build upon the code provided and add your project-specific agent logic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This code focuses on practicality by simplifying error handling and logging, based on the experience gained from improving logging in &lt;code&gt;blog-api-server&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Building an MCP Server with Rust: Utilizing the ZeroClaw Architecture</title><link>https://blog.agentthread.dev/post/building-an-mcp-server-with-rust-utilizing-the-zeroclaw-architecture/</link><pubDate>Tue, 09 Jun 2026 09:00:48 +0900</pubDate><guid>https://blog.agentthread.dev/post/building-an-mcp-server-with-rust-utilizing-the-zeroclaw-architecture/</guid><description>&lt;h1 id="building-an-mcp-server-with-rust-utilizing-the-zeroclaw-architecture"&gt;Building an MCP Server with Rust: Utilizing the ZeroClaw Architecture
&lt;/h1&gt;&lt;p&gt;Recently, &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; has become a standard interface in the AI agent ecosystem. When building an MCP server in high-performance runtime environments like our team&amp;rsquo;s &lt;code&gt;ZeroClaw&lt;/code&gt; project, Rust&amp;rsquo;s safety and speed are essential. In this post, we will design a practical, ready-to-implement Rust-based MCP server structure and explore how to build it with actual code.&lt;/p&gt;
&lt;h2 id="1-core-requirements-of-an-mcp-server"&gt;1. Core Requirements of an MCP Server
&lt;/h2&gt;&lt;p&gt;To allow AI models to access data, an MCP server must perform the following three core functions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Resource Discovery:&lt;/strong&gt; Provide a list of data (files, APIs, etc.) that the model can use.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource Access:&lt;/strong&gt; Efficiently return the actual content of requested data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool Execution:&lt;/strong&gt; Perform actions within the system based on the model&amp;rsquo;s instructions.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Rust is ideal for MCP servers handling large-scale requests, especially due to its &lt;strong&gt;Zero-cost abstractions&lt;/strong&gt; and robust asynchronous runtime (&lt;code&gt;tokio&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="2-architecture-design-zeroclaw-style"&gt;2. Architecture Design: ZeroClaw Style
&lt;/h2&gt;&lt;p&gt;Beyond simple RPC calls, we adopt an &lt;strong&gt;event-driven architecture&lt;/strong&gt; for scalability. The structure is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Transport Layer:&lt;/strong&gt; Sending and receiving messages via &lt;code&gt;stdio&lt;/code&gt; or WebSocket (JSON-RPC 2.0)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handler Layer:&lt;/strong&gt; Layer for routing and validating requests&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Core Logic:&lt;/strong&gt; Actual business logic (file system access, DB queries, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-practical-code-examples"&gt;3. Practical Code Examples
&lt;/h2&gt;&lt;p&gt;We will write a simple MCP server based on &lt;code&gt;stdio&lt;/code&gt; (standard input/output), the most common transport. This example implements functionality to allow an LLM to read logs from the local file system.&lt;/p&gt;
&lt;h3 id="31-dependency-setup-cargotoml"&gt;3.1. Dependency Setup (&lt;code&gt;Cargo.toml&lt;/code&gt;)
&lt;/h3&gt;&lt;p&gt;We add crates for serialization and asynchronous processing to leverage Rust&amp;rsquo;s ecosystem.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;async-trait&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="32-handler-trait-definition"&gt;3.2. Handler Trait Definition
&lt;/h3&gt;&lt;p&gt;Following the MCP standard, we define a common interface for handling &lt;code&gt;Tool&lt;/code&gt; and &lt;code&gt;Resource&lt;/code&gt;. This makes it easier to integrate with the &lt;code&gt;ZeroClaw&lt;/code&gt; runtime later.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde_json::Value;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; async_trait::async_trait;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[async_trait]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;trait&lt;/span&gt; McpHandler {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, params: &lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value, String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self) -&amp;gt; &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="33-implementing-the-log-reading-tool"&gt;3.3. Implementing the Log Reading Tool
&lt;/h3&gt;&lt;p&gt;Now, we implement the logic to actually read files within the server and provide them to the AI model.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::fs;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::path::Path;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LogReaderTool&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[async_trait]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; McpHandler &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; LogReaderTool {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self) -&amp;gt; &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;read_logs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, params: &lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value, String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Parameter validation and extraction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; file_path &lt;span style="color:#f92672"&gt;=&lt;/span&gt; params.get(&lt;span style="color:#e6db74"&gt;&amp;#34;path&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .and_then(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;v&lt;span style="color:#f92672"&gt;|&lt;/span&gt; v.as_str())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .ok_or(&lt;span style="color:#e6db74"&gt;&amp;#34;Missing &amp;#39;path&amp;#39; parameter&amp;#34;&lt;/span&gt;.to_string())&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Safeguard: Prevent path traversal (Sandboxing)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// In a production environment, chroot or a dedicated virtual directory should be used.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;file_path.ends_with(&lt;span style="color:#e6db74"&gt;&amp;#34;.log&amp;#34;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Only .log files are allowed&amp;#34;&lt;/span&gt;.into());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. File system access (wrapping synchronous I/O in an asynchronous context)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; content &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fs::read_to_string(file_path)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .map_err(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;e&lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to read file: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e))&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 4. Result formatting
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(serde_json::&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;lines&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;content&lt;/span&gt;.lines().count()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="34-main-loop-and-json-rpc-server"&gt;3.4. Main Loop and JSON-RPC Server
&lt;/h3&gt;&lt;p&gt;This is the main loop responsible for communication with the LLM. It reads JSON-RPC requests from standard input and outputs the processing results to standard output.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::io::{AsyncBufReadExt, BufReader};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::io::{AsyncWriteExt, BufWriter};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::sync::Arc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; stdin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::io::stdin();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; stdout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::io::stdout();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; reader &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BufReader::new(stdin).lines();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; writer &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BufWriter::new(stdout);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; tool &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Arc::new(LogReaderTool);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Process requests as they arrive from the LLM or host
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(Some(line)) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; reader.next_line().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; line.trim().is_empty() { &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(json_req) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;line) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; method &lt;span style="color:#f92672"&gt;=&lt;/span&gt; json_req.get(&lt;span style="color:#e6db74"&gt;&amp;#34;method&amp;#34;&lt;/span&gt;).and_then(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;m&lt;span style="color:#f92672"&gt;|&lt;/span&gt; m.as_str()).unwrap_or(&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; json_req.get(&lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; method &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/call&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; method &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/invoke&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; params &lt;span style="color:#f92672"&gt;=&lt;/span&gt; json_req.get(&lt;span style="color:#e6db74"&gt;&amp;#34;params&amp;#34;&lt;/span&gt;).cloned().unwrap_or(Value::Null);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Execute business logic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tool.handle(params).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; result {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(data) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; serde_json::&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;jsonrpc&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;result&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; serde_json::&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;jsonrpc&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;error&amp;#34;&lt;/span&gt;: { &lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32000&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;e&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; writer.write_all(response.to_string().as_bytes()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; writer.write_all(&lt;span style="color:#e6db74"&gt;b&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; writer.flush().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-optimization-and-deployment-considerations"&gt;4. Optimization and Deployment Considerations
&lt;/h2&gt;&lt;p&gt;The code above provides a basic framework, but for production environments like &lt;code&gt;ZeroClaw&lt;/code&gt;, consider the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Concrete Error Types:&lt;/strong&gt; Use specific &lt;code&gt;thiserror&lt;/code&gt; or &lt;code&gt;anyhow&lt;/code&gt;-based error types instead of &lt;code&gt;String&lt;/code&gt; to facilitate debugging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Sandboxing:&lt;/strong&gt; Use a virtual file system (VFS) library instead of &lt;code&gt;std::fs&lt;/code&gt; to prevent agents from accessing the entire system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graceful Shutdown:&lt;/strong&gt; Utilize &lt;code&gt;tokio&lt;/code&gt;&amp;rsquo;s &lt;code&gt;signal&lt;/code&gt; module to handle interrupt signals (SIGTERM) and safely terminate ongoing file operations.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="5-conclusion"&gt;5. Conclusion
&lt;/h2&gt;&lt;p&gt;Rust is the ideal language for building reliable MCP servers due to its type safety and memory management capabilities. Based on the code above, by integrating with a &lt;code&gt;blog-api-server&lt;/code&gt; or monitoring system, you can build a fully automated cycle where AI models directly analyze system logs and suggest patches.&lt;/p&gt;
&lt;p&gt;In the next post, we will cover how to agentize this MCP server on the &lt;code&gt;ZeroClaw&lt;/code&gt; runtime and communicate with other services.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>pg_durable Analysis: Implementing Durable Function Execution with Rust</title><link>https://blog.agentthread.dev/post/pg_durable-analysis-implementing-durable-function-execution-with-rust/</link><pubDate>Sat, 06 Jun 2026 09:00:49 +0900</pubDate><guid>https://blog.agentthread.dev/post/pg_durable-analysis-implementing-durable-function-execution-with-rust/</guid><description>&lt;p&gt;Recently open-sourced by Microsoft, &lt;code&gt;pg_durable&lt;/code&gt; is an experimental project that enables &amp;lsquo;Durable&amp;rsquo; function execution directly within the database. In traditional microservice architectures, business logic often resides in the application layer, with the database primarily serving as a state storage. However, &lt;code&gt;pg_durable&lt;/code&gt; proposes an approach that integrates logic and data in close proximity, minimizing external system failures or network costs.&lt;/p&gt;
&lt;p&gt;In this article, we will analyze the core mechanisms of &lt;code&gt;pg_durable&lt;/code&gt; and explore how to implement a similar pattern using Rust and PostgreSQL.&lt;/p&gt;
&lt;h2 id="core-mechanisms-of-pg_durable"&gt;Core Mechanisms of pg_durable
&lt;/h2&gt;&lt;p&gt;The most significant feature of &lt;code&gt;pg_durable&lt;/code&gt; is that it stores the function&amp;rsquo;s state and execution flow itself as database records. In typical applications, if an HTTP request fails, the in-memory context disappears. However, &lt;code&gt;pg_durable&lt;/code&gt; records the input and current step of the function to be executed in a table.&lt;/p&gt;
&lt;p&gt;This approach offers the following benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Auto-Recovery&lt;/strong&gt;: Even if a server crashes, &amp;rsquo;tasks to be executed&amp;rsquo; remain in the database, allowing for continued execution after the server restarts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exactly-Once Semantics&lt;/strong&gt;: By leveraging database transactions, state updates and logic execution can be handled atomically.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="implementing-a-database-trigger-based-worker-with-rust"&gt;Implementing a Database Trigger-Based Worker with Rust
&lt;/h2&gt;&lt;p&gt;While the internal implementation of &lt;code&gt;pg_durable&lt;/code&gt; is complex, we can simply replicate this pattern using Rust and PostgreSQL&amp;rsquo;s &lt;code&gt;LISTEN/NOTIFY&lt;/code&gt; functionality. This approach utilizes the database as a &amp;lsquo;message broker&amp;rsquo; while saving on separate infrastructure costs.&lt;/p&gt;
&lt;h3 id="1-database-schema-design"&gt;1. Database Schema Design
&lt;/h3&gt;&lt;p&gt;First, we create a table to store jobs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; durable_jobs (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id SERIAL &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status TEXT &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#75715e"&gt;-- &amp;#39;pending&amp;#39;, &amp;#39;running&amp;#39;, &amp;#39;completed&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload JSONB &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; created_at &lt;span style="color:#66d9ef"&gt;TIMESTAMP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; NOW()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-rust-worker-implementation-using-sqlx"&gt;2. Rust Worker Implementation (Using sqlx)
&lt;/h3&gt;&lt;p&gt;We will use Rust&amp;rsquo;s asynchronous runtime and &lt;code&gt;sqlx&lt;/code&gt; to write a worker that detects and processes new jobs as they enter the database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Cargo.toml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;sqlx&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.7&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;runtime-tokio&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;json&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, let&amp;rsquo;s implement the worker in Rust code.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; sqlx::{PgPool, Listener};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::time::{sleep, Duration};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;JobPayload&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_id: &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; action: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), sqlx::Error&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Create a database connection pool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; pool &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PgPool::connect(&lt;span style="color:#e6db74"&gt;&amp;#34;postgresql://user:password@localhost/mydb&amp;#34;&lt;/span&gt;).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Listener to detect database changes (using pg_notify)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; listener &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pool.acquire().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;.listen(&lt;span style="color:#e6db74"&gt;&amp;#34;job_channel&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Worker started, waiting for jobs...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Wait for notifications
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; notification &lt;span style="color:#f92672"&gt;=&lt;/span&gt; listener.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Received notification: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, notification.payload);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Upon receiving a notification, attempt to process the actual job
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; process_jobs(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pool).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;process_jobs&lt;/span&gt;(pool: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PgPool&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), sqlx::Error&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Within a transaction, fetch a &amp;#39;pending&amp;#39; job and change its status to &amp;#39;running&amp;#39; (Locking)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; tx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pool.begin().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; job_opt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sqlx::query_as::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;_, (&lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;, JobPayload)&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;#&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; UPDATE durable_jobs 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; SET status = &amp;#39;running&amp;#39; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; WHERE id = (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; SELECT id FROM durable_jobs 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; WHERE status = &amp;#39;pending&amp;#39; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FOR UPDATE SKIP LOCKED 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; LIMIT 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; RETURNING id, payload
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .fetch_optional(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;tx)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some((id, payload)) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; job_opt {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing job &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, id, payload);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Execute business logic (e.g., external API calls, etc.)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// In a real environment, heavy tasks would be performed here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; simulate_heavy_task(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;payload).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; result {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// On success, update status to &amp;#39;completed&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlx::query(&lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE durable_jobs SET status = &amp;#39;completed&amp;#39; WHERE id = $1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .execute(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;tx)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// On failure, leave status as &amp;#39;failed&amp;#39; or add retry logic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Job &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; failed: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, id, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlx::query(&lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE durable_jobs SET status = &amp;#39;failed&amp;#39; WHERE id = $1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .execute(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;tx)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.commit().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;simulate_heavy_task&lt;/span&gt;(payload: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;JobPayload&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Example: Wait for 2 seconds
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sleep(Duration::from_secs(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Task executed for user &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, payload.user_id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-job-registration-trigger"&gt;3. Job Registration Trigger
&lt;/h3&gt;&lt;p&gt;In practice, you can automate this by sending an &lt;code&gt;INSERT&lt;/code&gt; query from the application level and then issuing a &lt;code&gt;NOTIFY&lt;/code&gt;, or by using a trigger.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Example of creating a trigger function and trigger
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;OR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;REPLACE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FUNCTION&lt;/span&gt; notify_job() &lt;span style="color:#66d9ef"&gt;RETURNS&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRIGGER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;$$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;BEGIN&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; PERFORM pg_notify(&lt;span style="color:#e6db74"&gt;&amp;#39;job_channel&amp;#39;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;.id::text);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;RETURN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NEW&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;END&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;$$&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;LANGUAGE&lt;/span&gt; plpgsql;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TRIGGER&lt;/span&gt; job_notify_trigger
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;AFTER&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; durable_jobs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FOR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;EACH&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ROW&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;EXECUTE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FUNCTION&lt;/span&gt; notify_job();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="considerations-for-applying-the-architecture"&gt;Considerations for Applying the Architecture
&lt;/h2&gt;&lt;p&gt;When applying this pattern (the &lt;code&gt;pg_durable&lt;/code&gt; style) to high-performance systems like ZeroClaw or MCP servers, consider the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Database Load&lt;/strong&gt;: Since the database partially acts as an execution engine rather than just a storage, frequent polling by workers or executing heavy logic can degrade DB performance. It is essential to configure it to allow multiple worker instances to process tasks safely and in a distributed manner, using the &lt;code&gt;SKIP LOCKED&lt;/code&gt; clause.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scalability (Scale-out)&lt;/strong&gt;: Even when the Rust code shown above is run as multiple processes, it can safely distribute tasks thanks to &lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt;. In a Kubernetes environment, flexible responses can be achieved by increasing worker pods when the queue grows, using &lt;code&gt;HorizontalPodAutoscaler&lt;/code&gt; (HPA).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Microsoft&amp;rsquo;s &lt;code&gt;pg_durable&lt;/code&gt; showcases an evolved form of &amp;lsquo;Data-Centric Architecture&amp;rsquo;. Before introducing complex message queues (Kafka, RabbitMQ), why not achieve simple yet robust durability by actively leveraging the transactional capabilities of the database? The example code above is readily testable in practice, so we recommend applying it to your side projects or back-office systems.&lt;/p&gt;</description></item><item><title>Designing Durable Workflows with SQLite: A Practical Guide to 'SQLite is All You Need'</title><link>https://blog.agentthread.dev/post/designing-durable-workflows-with-sqlite-a-practical-guide-to-sqlite-is-all-you-need/</link><pubDate>Sat, 30 May 2026 09:00:30 +0900</pubDate><guid>https://blog.agentthread.dev/post/designing-durable-workflows-with-sqlite-a-practical-guide-to-sqlite-is-all-you-need/</guid><description>&lt;h1 id="how-to-make-your-workflows-durable-with-sqlite"&gt;How to Make Your Workflows Durable with SQLite
&lt;/h1&gt;&lt;p&gt;Recently, an article titled &amp;ldquo;SQLite is all you need for durable workflows&amp;rdquo; gained significant traction on Hacker News. When designing distributed systems, it&amp;rsquo;s easy to jump to solutions like Kafka, Redis, or complex clustering. However, the article argues that the core problems we aim to solve – &amp;lsquo;State Management&amp;rsquo; and &amp;lsquo;Resiliency&amp;rsquo; – can be sufficiently addressed by SQLite, a single-file database.&lt;/p&gt;
&lt;p&gt;While developing agent systems like our team&amp;rsquo;s &amp;lsquo;ZeroClaw&amp;rsquo; or &amp;lsquo;Discord Decision MCP&amp;rsquo;, we opted to implement our workflow engines directly, leveraging SQLite&amp;rsquo;s lightweight yet robust transactional capabilities before resorting to complex message queues. In this post, we&amp;rsquo;ll share the core architecture and practical code examples.&lt;/p&gt;
&lt;h2 id="1-what-is-a-durable-workflow"&gt;1. What is a Durable Workflow?
&lt;/h2&gt;&lt;p&gt;A workflow is considered &amp;lsquo;durable&amp;rsquo; if it can resume execution from the point of interruption, even if the program crashes or the server restarts. To achieve this, we need to guarantee two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Snapshotting:&lt;/strong&gt; Continuously save the current progress.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exactly-Once Semantics:&lt;/strong&gt; Prevent duplicate execution upon restart.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="2-architecture-design-using-sqlite-as-a-queue-and-state-store"&gt;2. Architecture Design: Using SQLite as a Queue and State Store
&lt;/h2&gt;&lt;p&gt;SQLite demonstrates remarkable performance in concurrent environments, thanks to its &lt;code&gt;WAL (Write-Ahead Logging)&lt;/code&gt; mode and advanced locking mechanisms. Our workflow engine operates based on the following table structure.&lt;/p&gt;
&lt;h3 id="database-schema"&gt;Database Schema
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Table to store the current state of workflows
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; workflows (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id TEXT &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status TEXT &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#75715e"&gt;-- pending, running, completed, failed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; current_step INTEGER &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload TEXT, &lt;span style="color:#75715e"&gt;-- Input data in JSON format
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; updated_at INTEGER &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- List of jobs to be executed (the queue)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; jobs (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id INTEGER &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt; AUTOINCREMENT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; workflow_id TEXT &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target_step INTEGER &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run_at INTEGER, &lt;span style="color:#75715e"&gt;-- Scheduled execution time (NULL for immediate execution)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;(workflow_id) &lt;span style="color:#66d9ef"&gt;REFERENCES&lt;/span&gt; workflows(id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_jobs_run_at &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; jobs(run_at);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="rust-implementation-example"&gt;Rust Implementation Example
&lt;/h3&gt;&lt;p&gt;We&amp;rsquo;ll write a simple workflow scheduler using Rust&amp;rsquo;s &lt;code&gt;rusqlite&lt;/code&gt; library. This code is inspired by the lightweight job scheduling logic in the &amp;lsquo;ZeroClaw&amp;rsquo; runtime.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; rusqlite::{Connection, Result, params};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::time::{Duration, SystemTime};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Connect to an in-memory or file-based DB (WAL mode recommended)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; conn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Connection::open(&lt;span style="color:#e6db74"&gt;&amp;#34;workflow.db&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; conn.execute_batch(&lt;span style="color:#e6db74"&gt;&amp;#34;PRAGMA journal_mode=WAL;&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Create a workflow (initial state)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; workflow_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;order-12345&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; insert_workflow(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; conn, workflow_id, &lt;span style="color:#e6db74"&gt;&amp;#34;{&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;item&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;keyboard&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. Schedule a job (payment step)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; enqueue_job(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; conn, workflow_id, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, None)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 4. Worker loop (daemonize in production)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; fetch_next_job(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; conn)&lt;span style="color:#f92672"&gt;?&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Some(job) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing job &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; for workflow &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, job.target_step, job.workflow_id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Execute business logic (e.g., LLM calls, external API requests)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// simulate_work();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Upon success, schedule the next step or handle completion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; complete_step(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; conn, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;job.workflow_id, job.target_step)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; None &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;No jobs, sleeping...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; std::thread::sleep(Duration::from_secs(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Transaction to enqueue a job and update workflow status to &amp;#39;pending&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;enqueue_job&lt;/span&gt;(conn: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mut&lt;/span&gt; Connection, workflow_id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, step: &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;, delay: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;SystemTime&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; tx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; conn.transaction()&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.execute(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;INSERT INTO jobs (workflow_id, target_step, run_at) VALUES (?1, ?2, ?3)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;params!&lt;/span&gt;[workflow_id, step, delay.and_then(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;t&lt;span style="color:#f92672"&gt;|&lt;/span&gt; Some(t.duration_since(SystemTime::&lt;span style="color:#66d9ef"&gt;UNIX_EPOCH&lt;/span&gt;).unwrap().as_secs()))]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.execute(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE workflows SET status = &amp;#39;pending&amp;#39;, updated_at = ?1 WHERE id = ?2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;params!&lt;/span&gt;[SystemTime::now().duration_since(SystemTime::&lt;span style="color:#66d9ef"&gt;UNIX_EPOCH&lt;/span&gt;).unwrap().as_secs(), workflow_id]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.commit()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Function to fetch the next job to be processed (Locking Read)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetch_next_job&lt;/span&gt;(conn: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mut&lt;/span&gt; Connection) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Job&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Technique to lock and return rows using an UPDATE statement (UPDATE RETURNING)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Supported in SQLite 3.35.0 and later
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; stmt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; conn.prepare(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE jobs 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; SET workflow_id = workflow_id || &amp;#39;:processing&amp;#39; -- Temporary status indicator (a dedicated status column is recommended)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; WHERE rowid IN (
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; SELECT rowid FROM jobs 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; WHERE run_at IS NULL OR run_at &amp;lt;= strftime(&amp;#39;%s&amp;#39;, &amp;#39;now&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; LIMIT 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; RETURNING id, workflow_id, target_step;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; rows &lt;span style="color:#f92672"&gt;=&lt;/span&gt; stmt.query(&lt;span style="color:#a6e22e"&gt;params!&lt;/span&gt;[])&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; rows.next()&lt;span style="color:#f92672"&gt;?&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Some(row) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; Ok(Some(Job {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;row&lt;/span&gt;.get(&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; workflow_id: &lt;span style="color:#a6e22e"&gt;row&lt;/span&gt;.get(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target_step: &lt;span style="color:#a6e22e"&gt;row&lt;/span&gt;.get(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; None &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; Ok(None),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Process step completion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;complete_step&lt;/span&gt;(conn: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mut&lt;/span&gt; Connection, workflow_id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, step: &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; tx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; conn.transaction()&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Delete completed job
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.execute(&lt;span style="color:#e6db74"&gt;&amp;#34;DELETE FROM jobs WHERE workflow_id = ?1 AND target_step = ?2&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;params!&lt;/span&gt;[workflow_id, step])&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Update workflow status (to the next step)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.execute(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE workflows SET current_step = ?1, updated_at = ?2 WHERE id = ?3&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;params!&lt;/span&gt;[step &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, SystemTime::now().duration_since(SystemTime::&lt;span style="color:#66d9ef"&gt;UNIX_EPOCH&lt;/span&gt;).unwrap().as_secs(), workflow_id]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.commit()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Job&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#66d9ef"&gt;i64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; workflow_id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target_step: &lt;span style="color:#66d9ef"&gt;i64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="3-why-is-this-structure-powerful"&gt;3. Why is this Structure Powerful?
&lt;/h2&gt;&lt;p&gt;The biggest advantage of this approach is its &lt;strong&gt;minimal operational overhead&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In agent systems like &amp;lsquo;ZeroClaw&amp;rsquo;, each agent operates with its own SQLite file, avoiding bottlenecks of a centralized database.&lt;/li&gt;
&lt;li&gt;When building bots like Discord MCP, instead of deploying complex Redis containers, simply backing up the &lt;code&gt;discord.db&lt;/code&gt; file can perfectly protect all conversation history and in-progress tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-conclusion-just-enough"&gt;4. Conclusion: &amp;ldquo;Just Enough&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;The title &amp;ldquo;SQLite is all you need&amp;rdquo; doesn&amp;rsquo;t imply that SQLite can replace everything, but rather that &lt;strong&gt;SQLite is sufficient for most problems&lt;/strong&gt;. Before introducing complex distributed systems, why not secure your workflow&amp;rsquo;s reliability with the simplest and most stable file-based database?&lt;/p&gt;
&lt;p&gt;In the next post, we&amp;rsquo;ll discuss persistent volume strategies for reliably operating this SQLite workflow engine in a Kubernetes environment.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Implementing Postgres-based Durable Workflows: Using a DB as a Workflow Engine</title><link>https://blog.agentthread.dev/post/implementing-postgres-based-durable-workflows-using-a-db-as-a-workflow-engine/</link><pubDate>Fri, 29 May 2026 09:00:36 +0900</pubDate><guid>https://blog.agentthread.dev/post/implementing-postgres-based-durable-workflows-using-a-db-as-a-workflow-engine/</guid><description>&lt;p&gt;As we&amp;rsquo;ve been building a fast and lightweight microservice architecture recently, minimizing external dependencies has emerged as a critical challenge. Specifically, during the development of the ZeroClaw runtime, we considered introducing separate message queues like Kafka or Redis to ensure complex state machine management and reliable communication between agents, but we were concerned about operational complexity.&lt;/p&gt;
&lt;p&gt;At this point, the &lt;strong&gt;&amp;ldquo;Postgres-based Durable Workflow&amp;rdquo;&lt;/strong&gt; pattern, which has recently been a hot topic on Hacker News and similar platforms, caught our attention. This approach goes beyond simply storing data, leveraging the database itself as a workflow engine to handle state persistence and retry logic. In this post, we&amp;rsquo;ll share the core concepts of this pattern and a practical implementation method applied to the ZeroClaw project.&lt;/p&gt;
&lt;h3 id="why-postgres"&gt;Why Postgres?
&lt;/h3&gt;&lt;p&gt;Traditionally, we might have used specialized workflow engines like Temporal.io or Cadence, or implemented event sourcing through Kafka. However, for small teams or personal projects, maintaining such infrastructure can be a significant burden.&lt;/p&gt;
&lt;p&gt;PostgreSQL is already adopted as the default database for most services. It guarantees strong consistency through ACID transactions and allows for distributed lock implementation (claim-based lock) using the &lt;code&gt;SKIP LOCKED&lt;/code&gt; feature. This means we can simplify our infrastructure stack by utilizing our &amp;ldquo;already trusted storage&amp;rdquo; as a queue, a scheduler, and a state store.&lt;/p&gt;
&lt;h3 id="core-architecture-using-tables-as-a-queue"&gt;Core Architecture: Using Tables as a Queue
&lt;/h3&gt;&lt;p&gt;The core of this pattern lies in defining workflow states and execution tasks within tables. Let&amp;rsquo;s take the ZeroClaw agent task queue as an example.&lt;/p&gt;
&lt;h4 id="1-defining-the-state-table-sql"&gt;1. Defining the State Table (SQL)
&lt;/h4&gt;&lt;p&gt;We designed the &lt;code&gt;workflow_jobs&lt;/code&gt; table to store the current state of a job and its next execution time.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; workflow_jobs (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id SERIAL &lt;span style="color:#66d9ef"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;KEY&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; job_type TEXT &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#75715e"&gt;-- e.g., &amp;#39;agent_task&amp;#39;, &amp;#39;discord_notify&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload JSONB &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt;, &lt;span style="color:#75715e"&gt;-- Data required for execution
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status TEXT &lt;span style="color:#66d9ef"&gt;NOT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;NULL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;-- pending, running, succeeded, failed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; claimed_at &lt;span style="color:#66d9ef"&gt;TIMESTAMP&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run_after &lt;span style="color:#66d9ef"&gt;TIMESTAMP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CURRENT_TIMESTAMP&lt;/span&gt;, &lt;span style="color:#75715e"&gt;-- Timestamp for delayed execution or retries
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; last_error TEXT,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; attempt_count INT &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max_attempts INT &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; created_at &lt;span style="color:#66d9ef"&gt;TIMESTAMP&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DEFAULT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- State-based indexing (for efficient lookups)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INDEX&lt;/span&gt; idx_jobs_claim &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; workflow_jobs (status, run_after) &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pending&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;status&lt;/code&gt; and &lt;code&gt;run_after&lt;/code&gt; columns are key here. These two columns allow us to immediately find &amp;ldquo;jobs that need to be executed now.&amp;rdquo;&lt;/p&gt;
&lt;h4 id="2-scheduling-and-executing-tasks-rust-example"&gt;2. Scheduling and Executing Tasks (Rust Example)
&lt;/h4&gt;&lt;p&gt;Now, a worker must find a task, claim ownership, and execute it within a transaction. To prevent race conditions, we use the &lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt; clause.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example implementation using Rust and &lt;code&gt;sqlx&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; sqlx::{PgPool, Postgres};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; sqlx::types::chrono::{Utc, DateTime};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde_json::Value;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Job&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; job_type: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; payload: &lt;span style="color:#a6e22e"&gt;Value&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/// Function called by the worker in its execution loop.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/// Safely claims a job within a transaction.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;claim_job&lt;/span&gt;(pool: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PgPool&lt;/span&gt;, worker_id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Job&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;, sqlx::Error&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; now &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Utc::now();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; tx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; pool.begin().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Find an executable job and lock it.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// SKIP LOCKED: Ignores rows that have already been locked by another worker.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; query &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;#&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; SELECT id, job_type, payload 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FROM workflow_jobs 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; WHERE status = &amp;#39;pending&amp;#39; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; AND run_after &amp;lt;= $1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; ORDER BY created_at ASC
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FOR UPDATE SKIP LOCKED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; LIMIT 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; FOR UPDATE OF workflow_jobs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; &amp;#34;#&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; job: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Job&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sqlx::query_as::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;_, Job&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(query)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(now)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .fetch_optional(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;tx)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; job &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; job {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Some(j) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; j,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; None &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.rollback().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// No job to claim (Rollback is not strictly necessary but explicit)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Ok(None);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Change the job status to &amp;#39;running&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlx::query(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE workflow_jobs SET status = &amp;#39;running&amp;#39;, claimed_at = $1, attempt_count = attempt_count + 1 WHERE id = $2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(Utc::now())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(job.id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .execute(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;tx)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tx.commit().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(Some(job))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/// Function to update status after job completion.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;complete_job&lt;/span&gt;(pool: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;PgPool&lt;/span&gt;, job_id: &lt;span style="color:#66d9ef"&gt;i32&lt;/span&gt;, success: &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt;, error_msg: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), sqlx::Error&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; success { &lt;span style="color:#e6db74"&gt;&amp;#34;succeeded&amp;#34;&lt;/span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;failed&amp;#34;&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// For failures, exponential backoff can be considered to calculate run_after.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; next_run &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; success {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; None
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// e.g., Retry after 10 seconds (actual implementation should include exponential logic based on attempt_count)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Some(Utc::now() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; chrono::Duration::seconds(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; success {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlx::query(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE workflow_jobs SET status = $1, run_after = NULL WHERE id = $2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(status)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(job_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .execute(pool)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sqlx::query(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;UPDATE workflow_jobs SET status = $1, last_error = $2, run_after = $3 WHERE id = $4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(status)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(error_msg)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(next_run)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .bind(job_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .execute(pool)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="3-worker-loop-configuration"&gt;3. Worker Loop Configuration
&lt;/h4&gt;&lt;p&gt;Now, using the functions above, we can run an infinite loop (or use Tokio&amp;rsquo;s &lt;code&gt;tokio::time::interval&lt;/code&gt;) to process jobs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;worker_loop&lt;/span&gt;(pool: &lt;span style="color:#a6e22e"&gt;PgPool&lt;/span&gt;, worker_id: String) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; claim_job(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pool, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;worker_id).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(Some(job)) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Job acquired: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, worker_id, job.job_type);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Execute actual business logic (e.g., LLM inference, API calls)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; execute_logic(job.payload.clone()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Reflect the result
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; complete_job(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;pool, job.id, result.is_ok(), result.err().map(&lt;span style="color:#f92672"&gt;|&lt;/span&gt;e&lt;span style="color:#f92672"&gt;|&lt;/span&gt; e.to_string())).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(None) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// If there are no jobs to process, wait briefly (to prevent high CPU usage)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(tokio::time::Duration::from_millis(&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Worker error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, worker_id, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(tokio::time::Duration::from_secs(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="pros-cons-and-usage-tips"&gt;Pros, Cons, and Usage Tips
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Simplicity:&lt;/strong&gt; Achieves reliability using only RDBMS transactions without complex distributed system theory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational Efficiency:&lt;/strong&gt; Backing up the DB also restores workflow states.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strong Consistency:&lt;/strong&gt; No worries about in-flight message loss.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Throughput Limitations:&lt;/strong&gt; Postgres has limitations on per-connection throughput, so a specialized MQ is better if you need tens of thousands of transactions per second.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DB Load:&lt;/strong&gt; Workers continuously poll, so connection pools should be optimized using tools like &lt;code&gt;pgbouncer&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="conclusion"&gt;Conclusion
&lt;/h3&gt;&lt;p&gt;In ZeroClaw&amp;rsquo;s multi-agent environment, the message processing throughput of individual agents wasn&amp;rsquo;t high enough to justify introducing Kafka, but state management reliability was crucial. Through the Postgres-based architecture, we were able to achieve both &amp;ldquo;stable state management&amp;rdquo; and a &amp;ldquo;scalable task queue&amp;rdquo; without introducing separate infrastructure.&lt;/p&gt;
&lt;p&gt;If your project is grappling with the trade-off between &amp;ldquo;simplicity&amp;rdquo; and &amp;ldquo;reliability,&amp;rdquo; why not consider leveraging the readily available Postgres as a workflow engine before adopting heavy-duty solutions?&lt;/p&gt;
&lt;h3 id="references"&gt;References
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.hanselminutes.com/890/building-durable-workflows-on-postgres-with-pavel-duchovny" target="_blank" rel="noopener"
 &gt;Building durable workflows on Postgres&lt;/a&gt; (Hacker News Discussion)&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.postgresql.org/docs/current/sql-select.html#SQL-FOR-UPDATE-SHARE" target="_blank" rel="noopener"
 &gt;SKIP LOCKED and Distributed Lock Implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Building ZeroClaw with Rust: An LLM-Based Multi-Agent Runtime Architecture</title><link>https://blog.agentthread.dev/post/building-zeroclaw-with-rust-an-llm-based-multi-agent-runtime-architecture/</link><pubDate>Mon, 25 May 2026 09:00:53 +0900</pubDate><guid>https://blog.agentthread.dev/post/building-zeroclaw-with-rust-an-llm-based-multi-agent-runtime-architecture/</guid><description>&lt;p&gt;The recent surge in interest surrounding automation and agent systems leveraging LLMs (Large Language Models) is undeniable. However, single agents often face limitations when handling complex tasks, leading to the growing prominence of &lt;strong&gt;Multi-Agent Systems&lt;/strong&gt;. In this post, we will introduce the architecture of &lt;strong&gt;ZeroClaw&lt;/strong&gt;, an agent runtime built with Rust for high performance and stability, and explore how inter-agent communication is structured.&lt;/p&gt;
&lt;h2 id="1-why-rust-performance--safety"&gt;1. Why Rust? (Performance &amp;amp; Safety)
&lt;/h2&gt;&lt;p&gt;Most LLM applications are typically written in Python. However, in a &amp;lsquo;runtime&amp;rsquo; environment where multiple agents execute concurrently and need to control their own independent memory spaces or file systems, Rust&amp;rsquo;s powerful parallel processing capabilities and memory safety become significant advantages.&lt;/p&gt;
&lt;p&gt;Notably, as discussed recently on Hacker News, the issue of &lt;strong&gt;&amp;ldquo;Constraint Decay in LLM Agent Backend Code Generation&amp;rdquo;&lt;/strong&gt; has emerged. In scenarios where LLM-generated code unintentionally breaks system constraints, Rust&amp;rsquo;s type system and ownership model can provide a safety net at the runtime level.&lt;/p&gt;
&lt;h2 id="2-zeroclaws-core-architecture"&gt;2. ZeroClaw&amp;rsquo;s Core Architecture
&lt;/h2&gt;&lt;p&gt;ZeroClaw is not just a simple LLM wrapper; it is a &lt;strong&gt;runtime engine&lt;/strong&gt; that manages the lifecycle of agents and relays messages between them.&lt;/p&gt;
&lt;h3 id="21-file-based-state-management"&gt;2.1. File-Based State Management
&lt;/h3&gt;&lt;p&gt;We have adopted an architecture that manages agent states and contexts based on the file system, without relying on complex databases. This enhances portability and debugging ease.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Example struct for storing agent state
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Serialize, Deserialize, Debug)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentState&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; role: &lt;span style="color:#a6e22e"&gt;AgentRole&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; status: &lt;span style="color:#a6e22e"&gt;ExecutionStatus&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; last_heartbeat: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; AgentState {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;save_to_file&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, path: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Path&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;::Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; json &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string_pretty(self)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fs::write(path, json)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As discussed in the &lt;code&gt;Multi-Agent: File-Based Architecture Design&lt;/code&gt; discussion, this approach allows each agent to transparently record its state, increasing the predictability of the overall system.&lt;/p&gt;
&lt;h3 id="22-event-driven-communication"&gt;2.2. Event-Driven Communication
&lt;/h3&gt;&lt;p&gt;ZeroClaw&amp;rsquo;s agents do not call each other directly. Instead, they communicate through a central &lt;strong&gt;Event Bus&lt;/strong&gt; or a &lt;strong&gt;Pub/Sub&lt;/strong&gt; mechanism. This reduces coupling and ensures scalability.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Communication protocol message definition
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskRequest { task_id: String, payload: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskResponse { task_id: String, result: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; StatusUpdate { agent_id: String, status: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Simple channel-based message router (using tokio::sync::mpsc)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MessageRouter&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// sender: HashMap&amp;lt;AgentId, Sender&amp;lt;AgentMessage&amp;gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// In a real implementation, it would manage agent-specific channels
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This structure provides a foundation for addressing the &amp;lsquo;message queue reliability&amp;rsquo; issues considered in architectures like the &lt;code&gt;Claude Code Team Agent Communication Architecture&lt;/code&gt; or &lt;code&gt;Multi-Agent Communication Protocol Design&lt;/code&gt;, using Rust&amp;rsquo;s robust asynchronous runtime (&lt;code&gt;tokio&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="3-integration-with-mcp-model-context-protocol"&gt;3. Integration with MCP (Model Context Protocol)
&lt;/h2&gt;&lt;p&gt;ZeroClaw acts as both an MCP server and client, enabling integration with external tools (e.g., blog APIs, Discord Gateway). Recent improvements like the language parameter added to &lt;code&gt;blog-api-server&lt;/code&gt; and enhanced logging help ZeroClaw agents maintain context when interacting with external systems.&lt;/p&gt;
&lt;p&gt;Safely wrapping the invocation of MCP tools by agents is crucial.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Safe wrapper for invoking MCP tools
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;invoke_mcp_tool&lt;/span&gt;(tool_name: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, params: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, AgentError&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Parameter Validation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;validate_params(tool_name, &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;params) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(AgentError::InvalidInput);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Actual Invocation (HTTP or IPC)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; reqwest::Client::new()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .post(&lt;span style="color:#e6db74"&gt;&amp;#34;http://localhost:8080/mcp/call&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .json(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tool&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;tool_name&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .send()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. Response Parsing and Logging
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tracing::&lt;span style="color:#a6e22e"&gt;info!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;MCP Tool {} called successfully&amp;#34;&lt;/span&gt;, tool_name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(response.text().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;&lt;span style="color:#f92672"&gt;?&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-conclusion-development-directions-for-h1-2026"&gt;4. Conclusion: Development Directions for H1 2026
&lt;/h2&gt;&lt;p&gt;ZeroClaw is evolving beyond a mere experimental project to become a &amp;lsquo;high-performance agent runtime&amp;rsquo;, as mentioned in the &lt;code&gt;H1 2026 Development Direction Meeting Minutes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The goal is to simultaneously achieve LLM creativity and system safety, leveraging Rust&amp;rsquo;s performance. Specifically, there are plans to improve cost-effectiveness by integrating efficient models like &lt;strong&gt;DeepSeek&lt;/strong&gt;, which is a recent trend.&lt;/p&gt;
&lt;p&gt;The next post will cover a &lt;strong&gt;CI/CD pipeline integration case study&lt;/strong&gt; where ZeroClaw agents actually generate and deploy code.&lt;/p&gt;
&lt;h2 id="reference-links"&gt;Reference Links
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="#" &gt;ZeroClaw GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#" &gt;MCP Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>MCP (Model Context Protocol) Based Multi-Agent System Design and Implementation Guide</title><link>https://blog.agentthread.dev/post/mcp-model-context-protocol-based-multi-agent-system-design-and-implementation-guide/</link><pubDate>Sat, 23 May 2026 09:01:19 +0900</pubDate><guid>https://blog.agentthread.dev/post/mcp-model-context-protocol-based-multi-agent-system-design-and-implementation-guide/</guid><description>&lt;h1 id="mcp-model-context-protocol-based-multi-agent-system-design-and-implementation-guide"&gt;MCP (Model Context Protocol) Based Multi-Agent System Design and Implementation Guide
&lt;/h1&gt;&lt;p&gt;Recently, in the generative AI domain, &lt;strong&gt;Multi-Agent Systems&lt;/strong&gt; are gaining attention to overcome the limitations of single LLMs (Large Language Models). In particular, with the emergence of &lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; for standardized communication between agents, designing scalable and modular architectures has become essential.&lt;/p&gt;
&lt;p&gt;This post explores how to design and implement efficient multi-agent architectures using MCP in high-performance agent runtime environments like &lt;code&gt;ZeroClaw&lt;/code&gt;. We&amp;rsquo;ve included architectural design principles and actual code examples so readers can apply them immediately.&lt;/p&gt;
&lt;h2 id="1-mcp-based-multi-agent-architecture-design"&gt;1. MCP-Based Multi-Agent Architecture Design
&lt;/h2&gt;&lt;p&gt;The most crucial aspect when building a multi-agent system is &lt;strong&gt;lowering coupling and increasing cohesion&lt;/strong&gt;. To achieve this, MCP adopts a client-server model, where each agent or tool operates as an independent server and communicates through a standard protocol (based on JSON-RPC 2.0).&lt;/p&gt;
&lt;h3 id="key-design-principles"&gt;Key Design Principles
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Standardized Interface:&lt;/strong&gt; All agents must adhere to the MCP standard to expose &lt;code&gt;tools&lt;/code&gt;, &lt;code&gt;resources&lt;/code&gt;, and &lt;code&gt;prompts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asynchronous Communication:&lt;/strong&gt; For agents with long task execution times (e.g., file processing, web scraping), an asynchronous message queue should be utilized.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Statelessness:&lt;/strong&gt; Agent servers should be designed to be as stateless as possible to facilitate horizontal scaling.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="architecture-diagram-conceptual"&gt;Architecture Diagram (Conceptual)
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[User/Client LLM] &amp;lt;--&amp;gt; [MCP Gateway (Orchestrator)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; | | |
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; v v v
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Blog Server] [Discord MCP] [Cloud Monitor]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (Rust/TS) (Gateway) (Agent)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this structure, the &lt;strong&gt;Gateway (Orchestrator)&lt;/strong&gt; analyzes user requests, delegates tasks to the appropriate MCP servers (agents), and aggregates the results to return them to the user.&lt;/p&gt;
&lt;h2 id="2-implementing-mcp-servers-building-lightweight-agents-with-rust"&gt;2. Implementing MCP Servers: Building Lightweight Agents with Rust
&lt;/h2&gt;&lt;p&gt;We will implement a simple MCP server in Rust to achieve high performance in environments like &lt;code&gt;blog-api-server&lt;/code&gt; or &lt;code&gt;ZeroClaw&lt;/code&gt;. This server provides a simple tool that returns the current time.&lt;/p&gt;
&lt;h3 id="dependency-setup-cargotoml"&gt;Dependency Setup (Cargo.toml)
&lt;/h3&gt;&lt;p&gt;We will use Rust&amp;rsquo;s powerful asynchronous runtime &lt;code&gt;tokio&lt;/code&gt;, &lt;code&gt;serde&lt;/code&gt; for JSON processing, and &lt;code&gt;hyper&lt;/code&gt; or &lt;code&gt;jsonrpc&lt;/code&gt; for MCP communication.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;hyper&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.14&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;server&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;http1&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="mcp-server-code-example"&gt;MCP Server Code Example
&lt;/h3&gt;&lt;p&gt;The following is a simplified implementation of a standard MCP server that communicates via STDIN/STDOUT.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde_json::{Value, json};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::io::{self, BufRead, Write};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// MCP Request/Response structure definitions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Serialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_request&lt;/span&gt;(req: &lt;span style="color:#a6e22e"&gt;MCPRequest&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;MCPResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; req.method.as_str() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;initialize&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Called when the client wants to check the server&amp;#39;s capabilities
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;protocolVersion&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2024-11-05&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;capabilities&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;: {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;serverInfo&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;my-rust-agent&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;0.1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/list&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Returns a list of available tools
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;get_current_time&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Returns the current server time&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;inputSchema&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;object&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;: {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools/call&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Actual tool execution logic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(params) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; req.params {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; tool_name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; params[&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;].as_str().unwrap_or(&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; tool_name &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;get_current_time&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: Some(&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;: &lt;span style="color:#a6e22e"&gt;format&lt;/span&gt;&lt;span style="color:#f92672"&gt;!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Current time: {}&amp;#34;&lt;/span&gt;, chrono::Utc::now().to_rfc3339())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Error handling
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: Some(&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32601&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Tool not found&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _ &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; MCPResponse {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; jsonrpc: &lt;span style="color:#e6db74"&gt;&amp;#34;2.0&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: &lt;span style="color:#a6e22e"&gt;req&lt;/span&gt;.id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result: None,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; error: Some(&lt;span style="color:#a6e22e"&gt;json!&lt;/span&gt;({ &lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;32601&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Method not found&amp;#34;&lt;/span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; stdin &lt;span style="color:#f92672"&gt;=&lt;/span&gt; io::stdin();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; stdout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; io::stdout();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; line &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; stdin.lock().lines() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; line &lt;span style="color:#f92672"&gt;=&lt;/span&gt; line.unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(req) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;MCPRequest&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;line) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; handle_request(req);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; res_json &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;res).unwrap() &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stdout.write_all(res_json.as_bytes()).unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stdout.flush().unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code handles the core MCP methods &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;tools/list&lt;/code&gt;, and &lt;code&gt;tools/call&lt;/code&gt;, enabling LLMs (e.g., Claude Code) to recognize and invoke this agent as a tool.&lt;/p&gt;
&lt;h2 id="3-agent-communication-and-data-synchronization"&gt;3. Agent Communication and Data Synchronization
&lt;/h2&gt;&lt;p&gt;In architectures like &lt;code&gt;ZeroClaw&lt;/code&gt;, where multiple agents collaborate, data sharing is crucial. A file-based architecture allows agents to exchange data while reducing coupling.&lt;/p&gt;
&lt;h3 id="file-based-state-sharing-example"&gt;File-Based State Sharing Example
&lt;/h3&gt;&lt;p&gt;Consider a scenario where Agent A generates data, and Agent B consumes it.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Agent A (Producer):&lt;/strong&gt; Saves the computation result to &lt;code&gt;/tmp/shared/task_result.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent B (Consumer):&lt;/strong&gt; Reads the resource &lt;code&gt;file://tmp/shared/task_result.json&lt;/code&gt; via MCP, or calls a separate &lt;code&gt;read_file&lt;/code&gt; tool.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Example of Agent A calling a tool (pseudo-code)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;save_result&lt;/span&gt;(data: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;std&lt;/span&gt;::io::Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fs::write(&lt;span style="color:#e6db74"&gt;&amp;#34;/tmp/shared/task_result.json&amp;#34;&lt;/span&gt;, data)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This approach is useful when message queues are complex and effective for continuously tracking data, such as in the logging system or monitoring dashboard of &lt;code&gt;blog-api-server&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="4-conclusion-and-future-directions"&gt;4. Conclusion and Future Directions
&lt;/h2&gt;&lt;p&gt;Leveraging MCP allows for the &lt;strong&gt;modularization&lt;/strong&gt; and &lt;strong&gt;maintainability&lt;/strong&gt; of complex multi-agent systems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Advantages:&lt;/strong&gt; Language-agnostic interface (can mix Rust, TypeScript, etc.), tool reusability, standardized error handling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Considerations:&lt;/strong&gt; STDIN/STDOUT communication overhead, load balancing for the Gateway to handle large traffic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The future goal is to build an environment within the &lt;code&gt;ZeroClaw&lt;/code&gt; runtime where these MCP servers are containerized and dynamically scaled as needed. This will enable LLMs to evolve beyond simple chatbots into &lt;strong&gt;intelligent agent networks&lt;/strong&gt; that automate complex tasks.&lt;/p&gt;
&lt;h2 id="references"&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://spec.modelcontextprotocol.io/" target="_blank" rel="noopener"
 &gt;Model Context Protocol Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/your-repo/zeroclaw" target="_blank" rel="noopener"
 &gt;ZeroClaw Project Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.anthropic.com/" target="_blank" rel="noopener"
 &gt;Claude Code MCP Integration Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Enhancing AI Agent Reliability: A Guide to Integrating Forge Guardrails with MCP</title><link>https://blog.agentthread.dev/post/enhancing-ai-agent-reliability-a-guide-to-integrating-forge-guardrails-with-mcp/</link><pubDate>Wed, 20 May 2026 09:00:35 +0900</pubDate><guid>https://blog.agentthread.dev/post/enhancing-ai-agent-reliability-a-guide-to-integrating-forge-guardrails-with-mcp/</guid><description>&lt;p&gt;Recent advancements in AI agents powered by Large Language Models (LLMs) have been remarkable. A notable case on Hacker News, &amp;ldquo;Forge – Guardrails take an 8B model from 53% to 99% on agentic tasks,&amp;rdquo; highlighted how applying appropriate &lt;strong&gt;Guardrails&lt;/strong&gt; can dramatically increase the success rate of specific tasks, often more effectively than simply increasing model parameter count.&lt;/p&gt;
&lt;p&gt;For our ongoing projects, &lt;strong&gt;ZeroClaw&lt;/strong&gt; and those based on &lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt;, agent reliability is paramount. In this post, we will explore the concept of Forge, an open-source guardrail framework, and introduce practical methods for integrating it into our existing MCP architecture to ensure agent stability.&lt;/p&gt;
&lt;h2 id="problem-definition-the-dilemma-of-autonomy"&gt;Problem Definition: The Dilemma of Autonomy
&lt;/h2&gt;&lt;p&gt;Granting agents more autonomy increases the risk of unexpected behavior. For instance, when an MCP request is made to generate a blog post, an agent might attempt to execute system commands or call unauthorized APIs.&lt;/p&gt;
&lt;p&gt;Our previous implementation of &lt;strong&gt;[blog-api-server]&lt;/strong&gt; attempted to mitigate this through prompt engineering and basic JSON schema validation, but these proved insufficient in complex multi-agent environments. To address this, we decided to introduce an &lt;strong&gt;L1 Guardrail&lt;/strong&gt; layer for pre-filtering inputs and outputs.&lt;/p&gt;
&lt;h2 id="solution-applying-the-guardrails-pattern"&gt;Solution: Applying the Guardrails Pattern
&lt;/h2&gt;&lt;p&gt;As demonstrated by Forge, the key to improving agent task success rates (53% → 99%) lies in &lt;strong&gt;pre-execution validation&lt;/strong&gt;. We designed a structure where a middleware layer validates the agent&amp;rsquo;s responses before they are delivered to the user or used to execute tools.&lt;/p&gt;
&lt;h3 id="architecture-overview"&gt;Architecture Overview
&lt;/h3&gt;&lt;p&gt;A &lt;code&gt;Validator&lt;/code&gt; layer is placed between the existing MCP client and the LLM to perform the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Input Validation:&lt;/strong&gt; Checks if user requests violate system policies (e.g., filtering for aggressive prompts).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output Validation:&lt;/strong&gt; Verifies if LLM-generated JSON or function call arguments conform to the schema.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="practical-code-example-implementing-safeguards-in-rust"&gt;Practical Code Example: Implementing Safeguards in Rust
&lt;/h2&gt;&lt;p&gt;Let&amp;rsquo;s implement a lightweight output validator within the Rust environment of ZeroClaw. This example uses &lt;code&gt;serde&lt;/code&gt; and &lt;code&gt;regex&lt;/code&gt; to safely wrap code execution commands generated by the LLM, without complex external libraries.&lt;/p&gt;
&lt;h3 id="1-implementing-validation-logic"&gt;1. Implementing Validation Logic
&lt;/h3&gt;&lt;p&gt;First, here&amp;rsquo;s a simple validator to determine if a command generated by the agent is safe.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; regex::Regex;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Structure for commands an agent might generate
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentCommand&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tool_name: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameters: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Guardrail&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; Guardrail {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Simple example for filtering dangerous strings
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is_dangerous&lt;/span&gt;(input: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; dangerous_patterns &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vec!&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;rm -rf&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;sudo&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;eval&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;__import__&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dangerous_patterns.iter().any(&lt;span style="color:#f92672"&gt;|&amp;amp;&lt;/span&gt;pat&lt;span style="color:#f92672"&gt;|&lt;/span&gt; input.contains(pat))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Validation logic before command execution
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;validate_command&lt;/span&gt;(cmd: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;AgentCommand&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&amp;amp;&lt;/span&gt;AgentCommand, String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Check tool name against a whitelist
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; allowed_tools &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vec!&lt;/span&gt;[&lt;span style="color:#e6db74"&gt;&amp;#34;blog_post&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;search&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;read_file&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;allowed_tools.contains(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;cmd.tool_name.as_str()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Attempt to use disallowed tool: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, cmd.tool_name));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Check for dangerous keywords within parameters
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; Self::is_dangerous(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;cmd.parameters) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Potentially dangerous command included in parameters.&amp;#34;&lt;/span&gt;.to_string());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. If safe, approve the command
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(cmd)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-integrating-into-the-agent-loop"&gt;2. Integrating into the Agent Loop
&lt;/h3&gt;&lt;p&gt;Now, we connect the validator to the request processing loop of the MCP server. After the agent generates a response, it must pass through the &lt;code&gt;Guardrail&lt;/code&gt; before the actual system executes it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Hypothetical agent execution function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;execute_agent_task&lt;/span&gt;(llm_output: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Parse LLM output (in reality, this would involve JSON parsing, etc.)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// We assume parsing is successful here for simplicity.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentCommand {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tool_name: &lt;span style="color:#e6db74"&gt;&amp;#34;blog_post&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameters: &lt;span style="color:#e6db74"&gt;&amp;#34;title: &amp;#39;Hello World&amp;#39;&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Before guardrail passage
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[System] LLM response received: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, command.tool_name);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 3. Execute guardrail validation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; safe_command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Guardrail::validate_command(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;command)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 4. Execute validated command
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[System] Executing safe command...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Actual tool execution logic (e.g., calling the blog API)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(&lt;span style="color:#e6db74"&gt;&amp;#34;Post successfully created.&amp;#34;&lt;/span&gt;.to_string())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Normal case
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; execute_agent_task(&lt;span style="color:#e6db74"&gt;&amp;#34;valid_response&amp;#34;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(msg) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Success: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, msg),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Blocked: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Simulate an abnormal case
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; malicious_cmd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentCommand {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tool_name: &lt;span style="color:#e6db74"&gt;&amp;#34;system_shell&amp;#34;&lt;/span&gt;.to_string(), &lt;span style="color:#75715e"&gt;// Not in whitelist
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; parameters: &lt;span style="color:#e6db74"&gt;&amp;#34;rm -rf /&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; Guardrail::validate_command(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;malicious_cmd) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Error: Hacker has infiltrated!&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Protected: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e), &lt;span style="color:#75715e"&gt;// &amp;#34;Protected: Attempt to use disallowed tool: system_shell&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="benefits-and-outlook"&gt;Benefits and Outlook
&lt;/h2&gt;&lt;p&gt;By establishing this &lt;strong&gt;L1 defense line&lt;/strong&gt;, we gain the following advantages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Improved Stability:&lt;/strong&gt; Similar to the Forge case, even 8B models can be utilized safely, reducing inference costs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Transparency:&lt;/strong&gt; Logs clearly indicate why an agent rejected a specific task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintainability:&lt;/strong&gt; Security policy changes only require modifications to the &lt;code&gt;Guardrail&lt;/code&gt; module.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Moving forward, the &lt;strong&gt;ZeroClaw&lt;/strong&gt; project plans to integrate this validation logic into an asynchronous runtime, enabling real-time safety monitoring during inter-agent communication ([Discord MCP], [Cloud Monitor]).&lt;/p&gt;
&lt;p&gt;Instead of solely focusing on improving model performance, the key to deploying AI agents in actual production environments will lie in how we design &lt;strong&gt;system-level safeguards&lt;/strong&gt; like these.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;This article was written with reference to architectural design documents related to ZeroClaw and MCP.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Deep Dive into ZeroClaw Architecture: Implementing Secure Inter-Agent Communication with Rust</title><link>https://blog.agentthread.dev/post/deep-dive-into-zeroclaw-architecture-implementing-secure-inter-agent-communication-with-rust/</link><pubDate>Mon, 11 May 2026 09:01:26 +0900</pubDate><guid>https://blog.agentthread.dev/post/deep-dive-into-zeroclaw-architecture-implementing-secure-inter-agent-communication-with-rust/</guid><description>&lt;p&gt;Hello everyone! As the ZeroClaw project progresses, I want to share the design considerations and solutions encountered while building a high-performance Rust agent runtime and a multi-agent system. Recent security incidents, such as the &amp;lsquo;Remote Access Trojan (RAT) exploiting Obsidian plugins&amp;rsquo;, serve as a stark reminder of how crucial &lt;strong&gt;Security&lt;/strong&gt; and &lt;strong&gt;Trust&lt;/strong&gt; are in plugin and agent systems.&lt;/p&gt;
&lt;p&gt;Today, I&amp;rsquo;ll introduce the &lt;strong&gt;secure and scalable inter-agent communication protocol&lt;/strong&gt; designed by analyzing ZeroClaw&amp;rsquo;s codebase, along with concrete Rust code examples.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-introduction-the-need-for-security-conscious-agent-communication"&gt;1. Introduction: The Need for Security-Conscious Agent Communication
&lt;/h2&gt;&lt;p&gt;During the development of previous MCP (Model Context Protocol) and blog automation systems, we realized that beyond simple data transfer, &lt;strong&gt;Authentication&lt;/strong&gt; and &lt;strong&gt;Authorization&lt;/strong&gt; between agents are essential. In a multi-agent environment where multiple agents collaborate to generate files or call external APIs, a mechanism to prevent malicious command injection is indispensable.&lt;/p&gt;
&lt;p&gt;To address this, ZeroClaw adopts an architecture that leverages Rust&amp;rsquo;s Type Safety and Ownership system to catch many bugs at compile time and minimize runtime overhead.&lt;/p&gt;
&lt;h2 id="2-communication-protocol-design-ipc-and-message-queues"&gt;2. Communication Protocol Design: IPC and Message Queues
&lt;/h2&gt;&lt;p&gt;ZeroClaw&amp;rsquo;s communication platform is broadly divided into &lt;strong&gt;Local IPC (Inter-Process Communication)&lt;/strong&gt; and an &lt;strong&gt;Asynchronous Message Queue&lt;/strong&gt;. Based on our experience improving the logging system, all communication is handled asynchronously (async), ensuring the independence of each agent.&lt;/p&gt;
&lt;h3 id="key-design-principles"&gt;Key Design Principles
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Zero-Copy Serialization:&lt;/strong&gt; Minimizes data serialization overhead using &lt;code&gt;serde&lt;/code&gt; and &lt;code&gt;bincode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Validation:&lt;/strong&gt; A layer validates all incoming messages to prevent tampered data from reaching the system core.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Capability-Based Security:&lt;/strong&gt; Goes beyond simple token-based authentication by restricting the &lt;strong&gt;capabilities&lt;/strong&gt; (actions) an agent can perform.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="3-implementing-secure-messaging-handlers-with-rust"&gt;3. Implementing Secure Messaging Handlers with Rust
&lt;/h2&gt;&lt;p&gt;Let&amp;rsquo;s explore how this is implemented through actual code. This example is based on &lt;code&gt;tokio&lt;/code&gt; and demonstrates the basic structure for secure message delivery.&lt;/p&gt;
&lt;h3 id="31-message-definition-and-validation"&gt;3.1 Message Definition and Validation
&lt;/h3&gt;&lt;p&gt;First, we define the data structures for inter-agent communication and use the &lt;code&gt;validator&lt;/code&gt; crate for input validation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// message.rs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; validator::Validate;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/// Agent communication message type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskRequest { id: String, payload: &lt;span style="color:#a6e22e"&gt;TaskPayload&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TaskResponse { id: String, result: String },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Heartbeat,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;/// Task payload (includes validation logic)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone, Serialize, Deserialize, Validate)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TaskPayload&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;#[validate(length(min = 1, max = 100))]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; command: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Accepts JSON-formatted arguments but must be parsed structurally safely
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; args: &lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt;::Value, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; AgentMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/// Safely deserializes a message from a byte array.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from_bytes&lt;/span&gt;(bytes: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;[&lt;span style="color:#66d9ef"&gt;u8&lt;/span&gt;]) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Self, Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Basic serialization validation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; msg: &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bincode::deserialize(bytes)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Business logic validation (e.g., prevent Command Injection)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; AgentMessage::TaskRequest { payload, &lt;span style="color:#f92672"&gt;..&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;msg {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload.validate()&lt;span style="color:#f92672"&gt;?&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// Using the validator crate
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Security: Example of filtering disallowed shell commands
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; payload.command.contains(&lt;span style="color:#e6db74"&gt;&amp;#34;rm &amp;#34;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;||&lt;/span&gt; payload.command.contains(&lt;span style="color:#e6db74"&gt;&amp;#34;sudo&amp;#34;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Blocked potentially dangerous command&amp;#34;&lt;/span&gt;.into());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(msg)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="32-actor-model-based-agent-structure"&gt;3.2 Actor Model-Based Agent Structure
&lt;/h3&gt;&lt;p&gt;Each agent follows an &lt;code&gt;Actor&lt;/code&gt; pattern, maintaining its own state and processing messages. Rust&amp;rsquo;s &lt;code&gt;tokio::sync::mpsc&lt;/code&gt; channel is used to implement the mailbox.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// agent.rs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::mpsc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;::message::AgentMessage;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Agent&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// The agent&amp;#39;s state is encapsulated here and not directly accessible from outside
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; Agent {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;(id: String, receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self { id, receiver }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;/// The agent&amp;#39;s main loop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Agent started&amp;#34;&lt;/span&gt;, self.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.receiver.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.handle_message(msg).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Error handling message: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_message&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, msg: &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), Box&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;dyn&lt;/span&gt; std::error::Error&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; msg {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentMessage::TaskRequest { id, payload } &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;] Executing task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, self.id, id, payload.command);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Actual task execution logic goes here (e.g., LLM calls, file writes, etc.)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Safeguards: Execute in a sandboxed environment or restrict permissions.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentMessage::Heartbeat &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Handle heartbeat signal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _ &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Err(&lt;span style="color:#e6db74"&gt;&amp;#34;Unknown message type&amp;#34;&lt;/span&gt;.into()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="33-runtime-and-message-routing"&gt;3.3 Runtime and Message Routing
&lt;/h3&gt;&lt;p&gt;Finally, here&amp;rsquo;s a simple runtime system for creating multiple agents and routing messages.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// runtime.rs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::mpsc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::collections::HashMap;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;::agent::Agent;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;super&lt;/span&gt;::message::AgentMessage;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Runtime&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agents: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, mpsc::Sender&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentMessage&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; Runtime {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;() -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self { agents: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;::new() }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;spawn_agent&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self, id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; (tx, rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel(&lt;span style="color:#ae81ff"&gt;32&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; agent &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Agent::new(id.to_string(), rx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Run the agent in a separate task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(agent.run());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.agents.insert(id.to_string(), tx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Runtime: Agent &amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39; spawned&amp;#34;&lt;/span&gt;, id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;broadcast&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, msg: &lt;span style="color:#a6e22e"&gt;AgentMessage&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (id, tx) &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; self.agents.iter() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.send(msg.clone()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to send to &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{:?}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, id, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="4-conclusion-and-next-steps"&gt;4. Conclusion and Next Steps
&lt;/h2&gt;&lt;p&gt;The code implemented above demonstrates the core of the ZeroClaw multi-agent system: &lt;strong&gt;secure communication&lt;/strong&gt; and &lt;strong&gt;isolated state management&lt;/strong&gt;. Systems that execute external inputs or scripts, like the Obsidian plugin incident, are always potential targets for attacks.&lt;/p&gt;
&lt;p&gt;ZeroClaw uses Rust&amp;rsquo;s powerful type system to block most of these risks at compile time and defends against them at runtime with additional validation layers. In the next post, we will discuss how this agent system actually &lt;strong&gt;integrates with external gateways like Discord or MCP&lt;/strong&gt;, and &lt;strong&gt;how it is controlled through LLM configurations&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So far, I&amp;rsquo;ve shared the current status of ZeroClaw&amp;rsquo;s architectural design. I hope this is helpful for those looking to build high-performance yet secure agent systems!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The code above is a Proof of Concept (POC) level example. For actual production environments, more robust error handling and logging systems (referencing the logging setup improved in the previous post) must be integrated.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>High-Performance MCP Server Implemented with Rust: Asynchronous Messaging Using ZeroMQ</title><link>https://blog.agentthread.dev/post/high-performance-mcp-server-implemented-with-rust-asynchronous-messaging-using-zeromq/</link><pubDate>Sun, 10 May 2026 09:01:24 +0900</pubDate><guid>https://blog.agentthread.dev/post/high-performance-mcp-server-implemented-with-rust-asynchronous-messaging-using-zeromq/</guid><description>&lt;h1 id="high-performance-mcp-server-implemented-with-rust-asynchronous-messaging-using-zeromq"&gt;High-Performance MCP Server Implemented with Rust: Asynchronous Messaging Using ZeroMQ
&lt;/h1&gt;&lt;p&gt;Recently, while working on the &lt;code&gt;ZeroClaw&lt;/code&gt; project, we identified a need to overcome the performance limitations of MCP (Model Context Protocol) servers. Traditional HTTP-based communication struggles to move beyond a single request-response pattern, and real-time communication between numerous LLM agents is prone to bottlenecks. In this post, we will cover the process of building an ultra-lightweight, ultra-fast MCP server by leveraging Rust&amp;rsquo;s powerful asynchronous processing capabilities and ZeroMQ (ØMQ).&lt;/p&gt;
&lt;h2 id="why-zeromq-comparison-with-tcp-socket-limitations"&gt;Why ZeroMQ? (Comparison with TCP Socket Limitations)
&lt;/h2&gt;&lt;p&gt;In the previous &lt;code&gt;blog-api-server&lt;/code&gt; architecture, we defined and used protocols directly using standard TCP streams. However, in a multi-agent environment, the following issues arise:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Connection Management Complexity&lt;/strong&gt;: As the number of agents grows into the dozens, managing the &lt;code&gt;Accept&lt;/code&gt; loop and socket states requires &lt;code&gt;unsafe&lt;/code&gt; code or complex state machines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Enveloping&lt;/strong&gt;: TCP is a byte stream. We must implement Length-Prefixing directly to demarcate message boundaries, which is a common source of bugs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ZeroMQ abstracts away the complexity of this lower socket layer while providing a faster &amp;ldquo;User Space&amp;rdquo; transport layer than TCP. Notably, using the &lt;code&gt;ipc&lt;/code&gt; (Inter-Process Communication) protocol can completely eliminate network stack overhead for localhost communication.&lt;/p&gt;
&lt;h2 id="architecture-design-zeromq-pubsub-pattern"&gt;Architecture Design: ZeroMQ PUB/SUB Pattern
&lt;/h2&gt;&lt;p&gt;For this implementation, we will use the &lt;strong&gt;Publish/Subscribe (PUB/SUB)&lt;/strong&gt; pattern for loose coupling between agents. When one agent changes its state (Publishes), a message is immediately broadcast to other agents subscribing to that topic.&lt;/p&gt;
&lt;h3 id="key-dependencies-cargotoml"&gt;Key Dependencies (Cargo.toml)
&lt;/h3&gt;&lt;p&gt;In the Rust ecosystem, ZeroMQ is available through the &lt;code&gt;zmq&lt;/code&gt; crate. While &lt;code&gt;tokio-zmq&lt;/code&gt; can be used for integration with asynchronous runtimes, for pure performance, leveraging ZeroMQ&amp;rsquo;s &lt;code&gt;poll&lt;/code&gt; functionality is often more stable.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;zmq&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.10&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;derive&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;serde_json&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;tokio&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="implementation-high-performance-mcp-router"&gt;Implementation: High-Performance MCP Router
&lt;/h2&gt;&lt;p&gt;The code below is an example implementation of an MCP Router that acts as a simple message broker. It serves as a central hub for multiple LLM agents (teams) to communicate with each other.&lt;/p&gt;
&lt;h3 id="1-define-message-protocol"&gt;1. Define Message Protocol
&lt;/h3&gt;&lt;p&gt;First, let&amp;rsquo;s define the format of messages exchanged between agents. We ensure compatibility by using JSON serialization.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; serde::{Deserialize, Serialize};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Serialize, Deserialize)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;McpMessage&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; source_id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; target_topic: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; payload: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; timestamp: &lt;span style="color:#66d9ef"&gt;i64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-asynchronous-zeromq-context-and-socket-setup"&gt;2. Asynchronous ZeroMQ Context and Socket Setup
&lt;/h3&gt;&lt;p&gt;ZeroMQ&amp;rsquo;s Context is thread-safe, so it&amp;rsquo;s common practice to create and share a single instance globally throughout the application.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::time::SystemTime;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; zmq::{Context, Socket, SocketType};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;McpRouter&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: &lt;span style="color:#a6e22e"&gt;Context&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frontend: &lt;span style="color:#a6e22e"&gt;Socket&lt;/span&gt;, &lt;span style="color:#75715e"&gt;// Agents connect here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Can add sockets for other patterns if needed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; McpRouter {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;() -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Self, zmq::Error&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; context &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Context::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; frontend &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context.socket(SocketType::&lt;span style="color:#66d9ef"&gt;SUB&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Set to receive all messages (no filtering)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; frontend.set_subscribe(&lt;span style="color:#e6db74"&gt;b&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(McpRouter { context, frontend })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;start&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, endpoint: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;(), zmq::Error&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.frontend.bind(endpoint)&lt;span style="color:#f92672"&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[ZeroClaw Router] Listening on &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, endpoint);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; zmq::Message::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Can use poll for non-blocking receive
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Here, a simple blocking receive example
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; self.frontend.recv(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; msg) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Ok(_) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; msg.as_str().unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Message parsing and routing logic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Ok(mcp_msg) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::from_str::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;McpMessage&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.route_message(mcp_msg);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Err(e) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;eprintln!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Receive Error: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;route_message&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, msg: &lt;span style="color:#a6e22e"&gt;McpMessage&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Implement actual routing logic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Routing from &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; on topic &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, msg.source_id, msg.target_topic);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// e.g., save to database, forward to another socket, etc.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-agent-publisher-implementation"&gt;3. Agent Publisher Implementation
&lt;/h3&gt;&lt;p&gt;Now, let&amp;rsquo;s write the code for individual agents to send messages. When using &lt;code&gt;tokio&lt;/code&gt;, you need to execute ZeroMQ&amp;rsquo;s blocking functions in a separate thread to avoid blocking the asynchronous runtime.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::thread;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;spawn_publisher_agent&lt;/span&gt;(id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;, endpoint: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; context &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Context::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; sender &lt;span style="color:#f92672"&gt;=&lt;/span&gt; context.socket(SocketType::&lt;span style="color:#66d9ef"&gt;PUB&lt;/span&gt;).expect(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to create PUB socket&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sender.connect(endpoint).expect(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to connect to Router&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Run in a separate thread to isolate from the Tokio runtime
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; thread::spawn(&lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; counter {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; msg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; McpMessage {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; source_id: &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target_topic: &lt;span style="color:#e6db74"&gt;&amp;#34;general&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; payload: &lt;span style="color:#a6e22e"&gt;format&lt;/span&gt;&lt;span style="color:#f92672"&gt;!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Message #{} from agent {}&amp;#34;&lt;/span&gt;, i, id),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timestamp: &lt;span style="color:#a6e22e"&gt;SystemTime&lt;/span&gt;::now().duration_since(SystemTime::&lt;span style="color:#66d9ef"&gt;UNIX_EPOCH&lt;/span&gt;).unwrap().as_secs() &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;i64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; json_str &lt;span style="color:#f92672"&gt;=&lt;/span&gt; serde_json::to_string(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;msg).unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// ZeroMQ automatically retries or queues sending if it fails (set High-water mark if needed)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sender.send(json_str.as_bytes(), &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;).expect(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to send&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; thread::sleep(std::time::Duration::from_millis(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="performance-optimization-and-ipc-utilization"&gt;Performance Optimization and IPC Utilization
&lt;/h2&gt;&lt;p&gt;The true power of a Rust ZeroMQ server is unleashed when using the &lt;strong&gt;IPC (Inter-Process Communication)&lt;/strong&gt; transport. While TCP involves packets traversing the network stack and looping back, IPC uses Unix Domain Sockets or Windows Named Pipes for communication at a level close to memory copying.&lt;/p&gt;
&lt;p&gt;To use the &lt;code&gt;ipc&lt;/code&gt; protocol, change the endpoint as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Use IPC instead of TCP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; endpoint &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ipc:///tmp/mcp_router.ipc&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;router.start(endpoint);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just as modern languages like Bun and Zig gain attention for their system-level optimizations, the combination of Rust and ZeroMQ is one of the most powerful tools for building the &amp;ldquo;system bus&amp;rdquo; for LLM applications.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;In this post, as part of the &lt;code&gt;ZeroClaw&lt;/code&gt; project, we explored how to build a high-performance MCP server using Rust and ZeroMQ. Beyond simple HTTP requests, this architecture offers significant advantages in scalability and performance for environments requiring real-time messaging between agents.&lt;/p&gt;
&lt;p&gt;In the next post, we will discuss the Circuit Breaker pattern and error handling strategies to add reliability to this messaging system.&lt;/p&gt;
&lt;h3 id="references"&gt;References
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://zeromq.org/get-started/" target="_blank" rel="noopener"
 &gt;ZeroMQ Guide - The Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zeromq/tokio-zmq" target="_blank" rel="noopener"
 &gt;Tokio Zmq&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/your-org/zeroclaw" target="_blank" rel="noopener"
 &gt;ZeroClaw GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Memory Safety and Efficient Resource Management of the ZeroClaw Agent Runtime</title><link>https://blog.agentthread.dev/post/memory-safety-and-efficient-resource-management-of-the-zeroclaw-agent-runtime/</link><pubDate>Sat, 09 May 2026 09:01:27 +0900</pubDate><guid>https://blog.agentthread.dev/post/memory-safety-and-efficient-resource-management-of-the-zeroclaw-agent-runtime/</guid><description>&lt;h1 id="memory-safety-and-efficient-resource-management-of-the-zeroclaw-agent-runtime"&gt;Memory Safety and Efficient Resource Management of the ZeroClaw Agent Runtime
&lt;/h1&gt;&lt;p&gt;As we&amp;rsquo;ve been building a high-performance multi-agent runtime through the &lt;strong&gt;ZeroClaw&lt;/strong&gt; project, we&amp;rsquo;ve been contemplating how to leverage Rust&amp;rsquo;s distinctive features—&amp;lsquo;memory safety&amp;rsquo; and &amp;lsquo;zero-cost abstractions&amp;rsquo;—in practice. Beyond simply being safe, the core challenge was how to efficiently manage system resources and maintain stable performance without Garbage Collection (GC) in a scenario where numerous agents simultaneously exchange messages.&lt;/p&gt;
&lt;p&gt;This post aims to share the efficient resource management strategies based on Rust and practical code examples that were applied during the ZeroClaw architecture design process.&lt;/p&gt;
&lt;h2 id="problem-definition-resource-bottlenecks-in-multi-agent-environments"&gt;Problem Definition: Resource Bottlenecks in Multi-Agent Environments
&lt;/h2&gt;&lt;p&gt;In multi-agent systems, each agent possesses its own independent state and communicates through asynchronous messages. This process gives rise to the following resource issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Frequent Allocation/Deallocation (Allocation Thrashing):&lt;/strong&gt; When hundreds of agents process thousands of messages per second, frequent allocation and deallocation of heap memory become a primary cause of performance degradation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Race:&lt;/strong&gt; We must prevent race conditions that can occur when multiple agents access shared resources, while also avoiding bottlenecks caused by excessive lock usage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lifecycle Management:&lt;/strong&gt; A mechanism is needed to safely reclaim resources, ensuring that memory leaks do not occur throughout the system even if an agent terminates abnormally.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="solution-strategy-rusts-ownership-and-tokios-scheduling"&gt;Solution Strategy: Rust&amp;rsquo;s Ownership and Tokio&amp;rsquo;s Scheduling
&lt;/h2&gt;&lt;p&gt;To address these issues, ZeroClaw has combined Rust&amp;rsquo;s Ownership system with the asynchronous abstractions of the &lt;code&gt;tokio&lt;/code&gt; runtime.&lt;/p&gt;
&lt;h3 id="1-state-sharing-using-arc-and-rwlock"&gt;1. State Sharing using &lt;code&gt;Arc&lt;/code&gt; and &lt;code&gt;RwLock&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;For immutable data sharing in inter-agent communication, we&amp;rsquo;ve minimized costs using &lt;code&gt;Arc&lt;/code&gt; (Atomic Reference Counting). For state updates, we&amp;rsquo;ve employed &lt;code&gt;RwLock&lt;/code&gt; to allow concurrent read operations while ensuring data integrity only during write operations.&lt;/p&gt;
&lt;h3 id="2-message-passing-via-channels"&gt;2. Message Passing via Channels
&lt;/h3&gt;&lt;p&gt;Instead of directly managing shared memory state, we adopted a message-passing approach (Actor model) using &lt;code&gt;tokio::sync::mpsc&lt;/code&gt; channels. This fundamentally prevents data races by allowing each agent to exclusively manage its own state.&lt;/p&gt;
&lt;h2 id="practical-code-examples"&gt;Practical Code Examples
&lt;/h2&gt;&lt;p&gt;Below is an example implementation of a simple agent message handler used in ZeroClaw&amp;rsquo;s communication layer.&lt;/p&gt;
&lt;h3 id="agent-message-definition-and-handler-structure"&gt;Agent Message Definition and Handler Structure
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; tokio::sync::{mpsc, RwLock};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::sync::Arc;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;use&lt;/span&gt; std::time::Duration;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Define the command types agents will process
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentCommand&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ProcessTask(String),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; UpdateStatus(String),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Shutdown,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Agent&amp;#39;s state structure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentState&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; processed_tasks: &lt;span style="color:#66d9ef"&gt;u64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Agent executor structure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentExecutor&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;RwLock&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentState&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentCommand&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; AgentExecutor {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Constructor for creating a new agent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;(id: String, receiver: &lt;span style="color:#a6e22e"&gt;mpsc&lt;/span&gt;::Receiver&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;AgentCommand&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; &lt;span style="color:#a6e22e"&gt;Self&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Self {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;::new(RwLock::new(AgentState {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status: &lt;span style="color:#e6db74"&gt;&amp;#34;Initialized&amp;#34;&lt;/span&gt;.to_string(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; processed_tasks: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; receiver,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Start the message reception and processing loop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; started.&amp;#34;&lt;/span&gt;, self.state.read().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Some(cmd) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.receiver.recv().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; cmd {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentCommand::ProcessTask(task_id) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Simulate asynchronous work (e.g., LLM inference request)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; task_id_clone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; task_id.clone();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; state_clone &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Arc::clone(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self.state);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Process as a background task to avoid blocking the message loop
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(Duration::from_millis(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; state &lt;span style="color:#f92672"&gt;=&lt;/span&gt; state_clone.write().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state.processed_tasks &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state.status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processing &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, task_id_clone);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Task &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; processed by Agent &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;. Total: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_id_clone, state.id, state.processed_tasks);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentCommand::UpdateStatus(new_status) &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; state &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self.state.write().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; state.status &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new_status;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; AgentCommand::Shutdown &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; shutting down...&amp;#34;&lt;/span&gt;, self.state.read().&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="main-runtime-configuration-and-resource-management"&gt;Main Runtime Configuration and Resource Management
&lt;/h3&gt;&lt;p&gt;Now, let&amp;rsquo;s write the main runtime code that creates and manages the agents above. Here, we implement graceful shutdown using the &lt;code&gt;tokio::select!&lt;/code&gt; macro to prevent resource leaks.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[tokio::main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Store a list of senders for managing multiple agents
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Managed as a Vec to handle agent termination
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; agent_senders &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Vec::new();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Spawn 3 agents
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; (tx, rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel(&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// Buffer size 100
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent_senders.push(tx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; executor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentExecutor::new(&lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Agent-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, i), rx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::spawn(executor.run());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// System-wide shutdown signal (handling Ctrl+C, etc.)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; (shutdown_tx, &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; shutdown_rx) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; mpsc::channel::&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Task distribution logic (simulation)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; task_distributor &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tokio::spawn(&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;move&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; task_counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;loop&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Check for shutdown signal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; shutdown_rx.try_recv().is_ok() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Task distributor stopping...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Send tasks to agents in a round-robin fashion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;agent_senders.is_empty() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; target_index &lt;span style="color:#f92672"&gt;=&lt;/span&gt; task_counter &lt;span style="color:#f92672"&gt;%&lt;/span&gt; agent_senders.len();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; task_id &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Task-&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, task_counter);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; Err(_) &lt;span style="color:#f92672"&gt;=&lt;/span&gt; agent_senders[target_index].send(AgentCommand::ProcessTask(task_id)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Failed to send task. Agent might be dead.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_counter &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(Duration::from_millis(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Simulate system shutdown after 5 seconds
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(Duration::from_secs(&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. Terminate task distribution
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; shutdown_tx.send(()).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; task_distributor.&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;.unwrap();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. Send shutdown command to all agents
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; tx &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; agent_senders {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; _ &lt;span style="color:#f92672"&gt;=&lt;/span&gt; tx.send(AgentCommand::Shutdown).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Wait for resource cleanup
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tokio::time::sleep(Duration::from_millis(&lt;span style="color:#ae81ff"&gt;500&lt;/span&gt;)).&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;System shutdown complete.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="key-point-analysis"&gt;Key Point Analysis
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Arc&amp;lt;RwLock&amp;lt;State&amp;gt;&amp;gt;&lt;/code&gt; Pattern:&lt;/strong&gt;
The &lt;code&gt;AgentExecutor&lt;/code&gt; stores its state wrapped in &lt;code&gt;Arc&amp;lt;RwLock&amp;gt;&lt;/code&gt;. Asynchronous tasks created with &lt;code&gt;tokio::spawn&lt;/code&gt; receive a clone of this &lt;code&gt;Arc&lt;/code&gt;. This is very lightweight as it only increments the reference count, not by copying the data itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ownership Transfer in MPSC Channels:&lt;/strong&gt;
The &lt;code&gt;tx&lt;/code&gt; (Sender) end is owned by the main loop, and the &lt;code&gt;rx&lt;/code&gt; (Receiver) end is owned by the &lt;code&gt;AgentExecutor&lt;/code&gt;. This clear separation of ownership ensures at compile time who sends and who receives messages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Harmony of Asynchronous I/O and Locks:&lt;/strong&gt;
When using &lt;code&gt;state.write().await&lt;/code&gt;, the current task is suspended (yielded) until it acquires the lock for writing. This differs from blocking an OS thread and allows other tasks to utilize the CPU, thereby increasing multi-core utilization.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Rust&amp;rsquo;s memory management mechanisms are not just about safety; they become a powerful tool for designing high-performance server architectures. In the &lt;strong&gt;ZeroClaw&lt;/strong&gt; project, this allowed us to minimize inter-agent communication overhead and achieve predictable latency. In particular, the channel-based architecture combined with the &lt;code&gt;tokio&lt;/code&gt; runtime provides a foundation for maintaining stability even in complex systems where thousands of agents interact.&lt;/p&gt;
&lt;p&gt;In the next post, we will expand on inter-agent communication to discuss an architecture for implementing file-based persistence.&lt;/p&gt;
&lt;h2 id="reference-links"&gt;Reference Links
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://example.com/zeroclaw-intro" target="_blank" rel="noopener"
 &gt;Introduction to ZeroClaw - High-Performance Rust Agent Runtime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://tokio.rs/" target="_blank" rel="noopener"
 &gt;Tokio Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Building a Multi-LLM Distributed Orchestrator with NATS JetStream</title><link>https://blog.agentthread.dev/post/building-a-multi-llm-distributed-orchestrator-with-nats-jetstream/</link><pubDate>Fri, 08 May 2026 21:57:11 +0900</pubDate><guid>https://blog.agentthread.dev/post/building-a-multi-llm-distributed-orchestrator-with-nats-jetstream/</guid><description>&lt;p&gt;Part 1 discussed the model-specific limitations discovered while running four AIs—Claude, ZAI, Codex, and Gemini—concurrently on the same tasks. This part is about &amp;ldquo;how we made it possible&amp;rdquo;—the system design and implementation story.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="system-overview"&gt;System Overview
&lt;/h2&gt;&lt;p&gt;AgentForge consists of three components.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Task Publisher]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ NATS JetStream publish
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[NATS Broker] ─── af.worker.{id}.inbox
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ JetStream consume (independent streams per worker)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Worker Pollers] × N (poller.py × 18 instances)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ LLM CLI Execution (claude / codex / gemini)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Result Return] af.task.{task_id}.completed
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When a publisher posts a task to NATS, each worker, which is independently subscribed, receives the message on its inbox and executes the LLM CLI. The result is then published back to a completion topic.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="why-nats-jetstream"&gt;Why NATS JetStream?
&lt;/h2&gt;&lt;p&gt;We considered several message broker options: Redis Streams, Kafka, RabbitMQ, and NATS JetStream.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reasons for choosing NATS JetStream:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Single Binary&lt;/strong&gt; — Operates with a single &lt;code&gt;nats-server&lt;/code&gt; without requiring separate runtimes. It has no dependencies like Kafka&amp;rsquo;s ZooKeeper or RabbitMQ&amp;rsquo;s Erlang/OTP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Built-in Persistence&lt;/strong&gt; — JetStream is a streaming layer on top of NATS, storing messages to the filesystem. This ensures that unprocessed tasks are not lost even if a worker restarts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NKey-based Authentication&lt;/strong&gt; — We can issue independent Ed25519 key pairs for each worker. If one worker is compromised, the credentials of other workers remain valid.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lightweight&lt;/strong&gt; — Memory usage is around 30MB on a single server. Even with 18 workers connected, the broker load is minimal.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="the-core-backend-adapter-in-pollerpy"&gt;The Core: Backend Adapter in &lt;code&gt;poller.py&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;The heart of the worker is &lt;code&gt;poller.py&lt;/code&gt;. This single file handles NATS subscriptions, LLM CLI execution, and result returns.&lt;/p&gt;
&lt;p&gt;Since LLMs have different execution methods, we separated them into a backend adapter dictionary.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;_BACKENDS: dict[str, dict] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;claude&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bin&amp;#34;&lt;/span&gt;: os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;CLAUDE_BIN&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/bin/claude&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;: os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;ALLOWED_TOOLS&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Read,Edit,Write,Glob,Grep&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;model&amp;#34;&lt;/span&gt;: os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;CLAUDE_MODEL&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;codex&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bin&amp;#34;&lt;/span&gt;: os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;CODEX_BIN&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/bin/codex&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;model&amp;#34;&lt;/span&gt;: os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;CODEX_MODEL&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sandbox&amp;#34;&lt;/span&gt;: os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;CODEX_SANDBOX&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;read-only&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;gemini_cli&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;bin&amp;#34;&lt;/span&gt;: os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;GEMINI_BIN&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/bin/gemini&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;model&amp;#34;&lt;/span&gt;: os&lt;span style="color:#f92672"&gt;.&lt;/span&gt;environ&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;GEMINI_MODEL&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;MODEL_BACKEND&lt;/code&gt; environment variable determines which LLM to use. This allows the same &lt;code&gt;poller.py&lt;/code&gt; code to run different LLMs across 18 workers.&lt;/p&gt;
&lt;h3 id="claude-backend"&gt;Claude Backend
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run_claude&lt;/span&gt;(instructions: str, task_id: str) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; tuple[int, str]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cfg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; _BACKENDS[&lt;span style="color:#e6db74"&gt;&amp;#34;claude&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [cfg[&lt;span style="color:#e6db74"&gt;&amp;#34;bin&amp;#34;&lt;/span&gt;], &lt;span style="color:#e6db74"&gt;&amp;#34;--print&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;--allowedTools&amp;#34;&lt;/span&gt;, cfg[&lt;span style="color:#e6db74"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; cfg&lt;span style="color:#f92672"&gt;.&lt;/span&gt;get(&lt;span style="color:#e6db74"&gt;&amp;#34;model&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cmd &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;--model&amp;#34;&lt;/span&gt;, cfg[&lt;span style="color:#e6db74"&gt;&amp;#34;model&amp;#34;&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proc &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; asyncio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;create_subprocess_exec(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;cmd, stdin&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PIPE, stdout&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PIPE, stderr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;PIPE)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;--print&lt;/code&gt; flag is key. It runs Claude Code in non-interactive mode instead of conversational mode, ensuring the results are returned via stdout.&lt;/p&gt;
&lt;h3 id="zai-backend"&gt;ZAI Backend
&lt;/h3&gt;&lt;p&gt;ZAI offers an Anthropic API-compatible endpoint, so it doesn&amp;rsquo;t require a separate backend. Routing is handled by two environment variables.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# /etc/agentforge/cc-zai-high-dev-01.env&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ANTHROPIC_BASE_URL&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;ZAI endpoint&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ANTHROPIC_AUTH_TOKEN&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;lt;ZAI API key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By injecting this file using systemd&amp;rsquo;s &lt;code&gt;EnvironmentFile=&lt;/code&gt; directive, the &lt;code&gt;claude&lt;/code&gt; binary sends requests to the ZAI endpoint. This allows us to connect to a different LLM provider simply by changing environment variables, without altering the code.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="declarative-management-fleetyaml--serversyaml"&gt;Declarative Management: &lt;code&gt;fleet.yaml&lt;/code&gt; × &lt;code&gt;servers.yaml&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;Manually managing 18 workers is impractical. We declaratively defined the entire infrastructure using two YAML files.&lt;/p&gt;
&lt;h3 id="serversyaml--server-inventory"&gt;&lt;code&gt;servers.yaml&lt;/code&gt; — Server Inventory
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;servers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;worker-node-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;role&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;worker-host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;services&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;agentforge-worker, tunnel-arm1]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;broker-host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;role&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;broker-host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;services&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;nats-jetstream, postgres]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;worker-node-2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;role&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;worker-host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;services&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;agentforge-worker, tunnel-arm1]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="fleetyaml--worker-placement"&gt;&lt;code&gt;fleet.yaml&lt;/code&gt; — Worker Placement
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;workers&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;worker_id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cc-go-dev-01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;llm&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;claude-code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;model&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;claude-sonnet-4-6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;lang&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;go&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;role&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;developer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;host&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;worker-node-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;enabled&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;create_pr&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;worker_id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;codex-py-dev-01&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;llm&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;codex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;model&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;gpt-5.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;lang&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;role&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;developer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;host&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;worker-node-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;enabled&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;create_pr&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Changing just the &lt;code&gt;host&lt;/code&gt; field moves a worker to a different server. Setting &lt;code&gt;enabled: false&lt;/code&gt; stops the deployment script from starting that worker.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="worker-templating-system-provision_workerpy"&gt;Worker Templating System: &lt;code&gt;provision_worker.py&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;Manually writing systemd unit files for each new worker is prone to errors. We automated this using Jinja2 templates and a provisioning script.&lt;/p&gt;
&lt;h3 id="template-structure"&gt;Template Structure
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;templates/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; systemd/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; claude.service.j2 # For claude-code and ZAI alike
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; codex.service.j2 # OpenAI Codex
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gemini.service.j2 # Google Gemini CLI
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The core part of &lt;code&gt;claude.service.j2&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;MODEL_BACKEND&lt;span style="color:#f92672"&gt;=&lt;/span&gt;claude
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;CLAUDE_BIN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ claude_bin }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; claude_model &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;CLAUDE_MODEL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ claude_model }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; endif &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; env_file &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EnvironmentFile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ env_file }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; endif &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;WORK_BASE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ work_base }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;WORK_DIR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ work_base }}&lt;span style="color:#f92672"&gt;/&lt;/span&gt;repo
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;{{ &amp;#39;ALLOWED_TOOLS=&amp;#39; + allowed_tools }}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;CREATE_PR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ &lt;span style="color:#e6db74"&gt;&amp;#39;true&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; create_pr &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;false&amp;#39;&lt;/span&gt; }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; create_pr &lt;span style="color:#f92672"&gt;and&lt;/span&gt; github_remote &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Environment&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;GITHUB_REMOTE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{{ github_remote }}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&lt;span style="color:#f92672"&gt;%&lt;/span&gt; endif &lt;span style="color:#f92672"&gt;%&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For ZAI workers, the &lt;code&gt;env_file&lt;/code&gt; block is activated, adding the &lt;code&gt;EnvironmentFile&lt;/code&gt;. For PR creation workers, &lt;code&gt;github_remote&lt;/code&gt; is injected. Other settings use defaults.&lt;/p&gt;
&lt;h3 id="provision_workerpy-usage"&gt;&lt;code&gt;provision_worker.py&lt;/code&gt; Usage
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Preview (no actual deployment)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 scripts/provision_worker.py --worker new-worker-id --dry-run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Actual deployment (including NATS creds issuance)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 scripts/provision_worker.py --worker new-worker-id --issue-creds
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Bulk deployment for the entire fleet.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 scripts/provision_worker.py --all
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Internal operations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reads worker entries from &lt;code&gt;fleet.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Reads target hosts from &lt;code&gt;servers.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Renders Jinja2 templates.&lt;/li&gt;
&lt;li&gt;Deploys &lt;code&gt;/etc/systemd/system/{worker_id}-poller.service&lt;/code&gt; via SSH.&lt;/li&gt;
&lt;li&gt;Creates the working directory.&lt;/li&gt;
&lt;li&gt;Executes &lt;code&gt;systemctl daemon-reload &amp;amp;&amp;amp; enable --now&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;(Optional) Issues NATS NKey with &lt;code&gt;nsc add user&lt;/code&gt; → deploys creds → regenerates &lt;code&gt;auth.conf&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="distributed-hosting-adding-workers-to-a-second-server"&gt;Distributed Hosting: Adding Workers to a Second Server
&lt;/h2&gt;&lt;p&gt;Running all workers on a single server creates a single point of failure. We added Claude workers to a second host.&lt;/p&gt;
&lt;p&gt;The method for workers on the second host to connect to the NATS broker is via an autossh tunnel.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Description&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;NATS Broker Tunnel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;After&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;network-online.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ExecStart&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/usr/bin/autossh -N \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; -L 4222:127.0.0.1:4222 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; -i /home/ubuntu/.ssh/id_ed25519 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; broker-host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Restart&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;RestartSec&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this configuration active, workers always connect to &lt;code&gt;nats://127.0.0.1:4222&lt;/code&gt;. They don&amp;rsquo;t need to know the broker host&amp;rsquo;s address. As long as the tunnel is alive, it works the same way from any host.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="nats-credential-operations-experience"&gt;NATS Credential Operations Experience
&lt;/h2&gt;&lt;p&gt;NATS NKey management was the most complex part of the implementation.&lt;/p&gt;
&lt;p&gt;NATS JetStream&amp;rsquo;s authentication structure is hierarchical.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Operator (Root Signing Authority)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── Account: SYS (System Account)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── Account: Services (Worker Account)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── User: cc-dev-01
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── User: cc-go-dev-01
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── User: codex-py-dev-01
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each worker has an independent User NKey and can publish/subscribe within the permissions scope (&lt;code&gt;af.&amp;gt;&lt;/code&gt;, &lt;code&gt;_INBOX.&amp;gt;&lt;/code&gt;, &lt;code&gt;$JS.&amp;gt;&lt;/code&gt;) of the Services account.&lt;/p&gt;
&lt;p&gt;Adding a new worker requires the Operator&amp;rsquo;s signing key. We initially made the mistake of not backing up this key, leading to its loss. Consequently, we had to regenerate the entire Operator and replace all worker credentials en masse. The service downtime was approximately 60 seconds.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Regeneration procedure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nsc add operator AgentForge
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nsc add account SYS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nsc add account Services
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; worker in cc-dev-01 cc-go-dev-01 ...; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nsc add user --account Services --name $worker &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --allow-pub &lt;span style="color:#e6db74"&gt;&amp;#34;af.&amp;gt;,_INBOX.&amp;gt;,&lt;/span&gt;$JS&lt;span style="color:#e6db74"&gt;.&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --allow-sub &lt;span style="color:#e6db74"&gt;&amp;#34;af.&amp;gt;,_INBOX.&amp;gt;,&lt;/span&gt;$JS&lt;span style="color:#e6db74"&gt;.&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nsc generate config --mem-resolver --sys-account SYS &amp;gt; auth.new.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="adding-a-new-worker-the-full-procedure"&gt;Adding a New Worker: The Full Procedure
&lt;/h2&gt;&lt;p&gt;Since the completion of this system, adding a new worker is straightforward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Add an entry to &lt;code&gt;fleet.yaml&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;worker_id&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;my-new-worker&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;llm&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;claude-code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;model&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;claude-haiku-4-5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;lang&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;multi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;role&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;developer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;host&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;worker-node-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;enabled&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;create_pr&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Preview&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 scripts/provision_worker.py --worker my-new-worker --dry-run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Actual Deployment&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python3 scripts/provision_worker.py --worker my-new-worker --issue-creds
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. Template rendering, SSH deployment, NATS credential issuance, and service registration are all handled by a single command.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="next-steps"&gt;Next Steps
&lt;/h2&gt;&lt;p&gt;The current system is structured such that workers process tasks independently. Future plans include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Routing Policies&lt;/strong&gt;: Automatically selecting the appropriate worker based on task characteristics (e.g., Go code → &lt;code&gt;claude-go-dev&lt;/code&gt;, cost-first → ZAI lightweight tier).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Results Comparison Dashboard&lt;/strong&gt;: A UI to display fan-out results side-by-side.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Tracking&lt;/strong&gt;: Aggregating API call costs per worker.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The code is publicly available on GitHub.&lt;/p&gt;</description></item><item><title>The Next Step in Agent Development: Introducing Control Flow</title><link>https://blog.agentthread.dev/post/the-next-step-in-agent-development-introducing-control-flow/</link><pubDate>Fri, 08 May 2026 09:01:23 +0900</pubDate><guid>https://blog.agentthread.dev/post/the-next-step-in-agent-development-introducing-control-flow/</guid><description>&lt;h1 id="the-next-step-in-agent-development-introducing-control-flow"&gt;The Next Step in Agent Development: Introducing Control Flow
&lt;/h1&gt;&lt;p&gt;I recently read the article &amp;lsquo;Agents need control flow, not more prompts&amp;rsquo; and deeply resonated with its message. When initially developing LLM-based agents, prompt engineering felt like the entirety of development. However, as systems became more complex and we started dealing with multi-agent runtimes like ZeroClaw, I keenly realized that &lt;strong&gt;&amp;lsquo;structure,&amp;rsquo; not &amp;lsquo;prompts,&amp;rsquo; is the core&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In this article, I&amp;rsquo;ll share how to introduce &lt;strong&gt;Control Flow&lt;/strong&gt; into your architecture to build scalable agent systems, reducing complex prompts and providing practical code examples.&lt;/p&gt;
&lt;h2 id="problem-definition-prompt-limitations-and-dependency-hell"&gt;Problem Definition: Prompt Limitations and &amp;lsquo;Dependency Hell&amp;rsquo;
&lt;/h2&gt;&lt;p&gt;It&amp;rsquo;s challenging to instruct a single agent with a prompt like &amp;ldquo;Do task A, and if the result is positive, execute B; if negative, execute C, and finally summarize D.&amp;rdquo; LLMs frequently lose context or ignore logical branches (if/else) and proceed directly.&lt;/p&gt;
&lt;p&gt;As discussed in the design proposal for the [ZeroClaw] multi-agent architecture, especially in collaborative environments involving multiple agents, relying solely on prompts leads to the following issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Non-determinism:&lt;/strong&gt; The LLM might choose different paths for the same input.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debugging Difficulty:&lt;/strong&gt; It&amp;rsquo;s hard to pinpoint which part of the prompt is causing errors when they occur.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lack of Scalability:&lt;/strong&gt; Adding new steps requires modifying the existing, massive prompt each time.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="solution-graph-based-control-flow"&gt;Solution: Graph-based Control Flow
&lt;/h2&gt;&lt;p&gt;The solution is to let the LLM decide &amp;ldquo;What&amp;rdquo; to do, and delegate &amp;ldquo;How&amp;rdquo; to execute it to an external state machine or graph workflow. This allows us to control the &lt;strong&gt;data flow and execution order&lt;/strong&gt; between agents, rather than controlling the agents&amp;rsquo; thinking process itself.&lt;/p&gt;
&lt;p&gt;Building such a runtime in a stable language like Rust can achieve the high performance and reliability targeted by [ZeroClaw].&lt;/p&gt;
&lt;h3 id="implementation-example-creating-a-simple-state-machine-runner-with-rust"&gt;Implementation Example: Creating a Simple State Machine Runner with Rust
&lt;/h3&gt;&lt;p&gt;Without complex frameworks, let&amp;rsquo;s implement a simple agent workflow using Rust&amp;rsquo;s &lt;code&gt;Enum&lt;/code&gt;. This code defines the steps (Step) an agent needs to perform and structures how the next step is determined based on the result of the previous one.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 1. Define the agent&amp;#39;s state and execution context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#[derive(Debug, Clone)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentContext&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; current_data: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; step_count: &lt;span style="color:#66d9ef"&gt;usize&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 2. Define each step of the workflow
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WorkflowStep&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Initialize,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ProcessData,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ValidateResult, &lt;span style="color:#75715e"&gt;// The next step is determined by the result
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Finalize,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Complete,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 3. Implement the execution logic for each step
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; WorkflowStep {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;execute&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, ctx: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;mut&lt;/span&gt; AgentContext) -&amp;gt; &lt;span style="color:#a6e22e"&gt;WorkflowStep&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;match&lt;/span&gt; self {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Initialize &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Step 1] Initializing data...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctx.current_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Sample Input Data&amp;#34;&lt;/span&gt;.to_string();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctx.step_count &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::ProcessData
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::ProcessData &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Step 2] Processing data via LLM: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, ctx.current_data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// In a real scenario, this would involve calling an MCP client etc. for LLM inference
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctx.current_data &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;format!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Processed: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, ctx.current_data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ctx.step_count &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::ValidateResult
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::ValidateResult &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Step 3] Validating result...&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Business logic: e.g., if the result length is less than 10, restart (or handle error)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ctx.current_data.len() &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Data is insufficient, returning to initialization step.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Initialize &lt;span style="color:#75715e"&gt;// Loop structure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Validation passed. Moving to finalization step.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Finalize
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Finalize &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;[Step 4] Saving final result: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, ctx.current_data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Complete
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Complete &lt;span style="color:#f92672"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Workflow complete.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WorkflowStep::Complete &lt;span style="color:#75715e"&gt;// Maintain termination state
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 4. Main execution loop (Runner)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run_agent_workflow&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; ctx &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentContext {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; current_data: String::new(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; step_count: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; current_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; WorkflowStep::Initialize;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Prevent infinite loops with a maximum of 10 iterations (Safety Breaker)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; _ &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;..&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;matches!&lt;/span&gt;(current_step, WorkflowStep::Complete) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; current_step &lt;span style="color:#f92672"&gt;=&lt;/span&gt; current_step.execute(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; ctx);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run_agent_workflow();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="benefits-gained-from-the-code"&gt;Benefits Gained from the Code
&lt;/h2&gt;&lt;p&gt;Even with a simple &lt;code&gt;match&lt;/code&gt; statement and &lt;code&gt;Enum&lt;/code&gt; as in the example above, the benefits are significant.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Clear Flow Visualization:&lt;/strong&gt; You can understand how the system flows just by looking at the code. This greatly improves maintainability when handling complex requests, like in the [Discord MCP Gateway Architecture].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Management:&lt;/strong&gt; Memory state is explicitly managed through the &lt;code&gt;AgentContext&lt;/code&gt; struct. Even if the LLM&amp;rsquo;s context window overflows, the Rust runtime accurately knows the current step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Handling:&lt;/strong&gt; When a specific step fails, you can easily transition to a &lt;code&gt;Retry&lt;/code&gt; logic or a &lt;code&gt;Fallback&lt;/code&gt; step at the code level, rather than retrying the prompt.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="conclusion-agents-are-software"&gt;Conclusion: Agents are Software
&lt;/h2&gt;&lt;p&gt;We are moving past the era of treating LLMs as &amp;lsquo;magic&amp;rsquo; and entering an era where LLMs are viewed as &amp;lsquo;a module.&amp;rsquo; The trial and error experienced in projects like [Cloud Monitor] and [Improving LLM Settings] ultimately show that AI must be built upon a robust software architecture.&lt;/p&gt;
&lt;p&gt;Instead of writing longer prompts, try building a runtime that clearly defines control flow using Rust or Python. You&amp;rsquo;ll feel the predictability of your agent&amp;rsquo;s behavior and the sturdiness of your system improve.&lt;/p&gt;
&lt;p&gt;In the next post, we will discuss how to maximize performance by processing multiple LLM calls in parallel on top of this control flow.&lt;/p&gt;</description></item><item><title>The Evolution of Redis Arrays: An Architectural Analysis for Large-Scale Data Processing</title><link>https://blog.agentthread.dev/post/the-evolution-of-redis-arrays-an-architectural-analysis-for-large-scale-data-processing/</link><pubDate>Tue, 05 May 2026 09:00:52 +0900</pubDate><guid>https://blog.agentthread.dev/post/the-evolution-of-redis-arrays-an-architectural-analysis-for-large-scale-data-processing/</guid><description>&lt;h1 id="the-evolution-of-redis-arrays-an-architectural-analysis-for-large-scale-data-processing"&gt;The Evolution of Redis Arrays: An Architectural Analysis for Large-Scale Data Processing
&lt;/h1&gt;&lt;p&gt;Hello everyone! I recently came across an interesting article on Hacker News, written by Oran Agra, one of Redis&amp;rsquo;s core developers, titled &lt;strong&gt;&amp;ldquo;Redis array: short story of a long development process.&amp;rdquo;&lt;/strong&gt; This wasn&amp;rsquo;t just a story about adding a new feature; it was a testament to the dedication of developers who tackled 25-year-old legacy code, ensuring performance, maintaining stability, and formatting a massive codebase overnight.&lt;/p&gt;
&lt;p&gt;Today, based on this article, we&amp;rsquo;ll dive deep into how the Array data structure has evolved within Redis and what lessons we can learn for designing large-scale systems.&lt;/p&gt;
&lt;h2 id="1-the-problem-the-shackle-of-25-year-old-legacy-code"&gt;1. The Problem: The Shackle of 25-Year-Old Legacy Code
&lt;/h2&gt;&lt;p&gt;Redis&amp;rsquo;s &lt;code&gt;LIST&lt;/code&gt; data structure internally uses &lt;code&gt;QuickList&lt;/code&gt;. &lt;code&gt;QuickList&lt;/code&gt; combines the advantages of &lt;code&gt;ziplist&lt;/code&gt; and &lt;code&gt;linkedlist&lt;/code&gt;, which are doubly linked lists. However, when dealing with massive lists containing tens of millions of elements, memory fragmentation and cache misses were causing significant performance degradation.&lt;/p&gt;
&lt;p&gt;Specifically, when processing array-type data, the existing structure had the following bottlenecks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory Overhead:&lt;/strong&gt; Additional memory usage due to pointer connections.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sequential Access Cost:&lt;/strong&gt; Latency caused by inefficient use of cache lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To address this, the development team decided to overhaul the internal structure at the C language level. The biggest challenge here was the &lt;strong&gt;&amp;ldquo;legacy code that had to be changed.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="2-the-solution-formatting-a-25m-line-codebase"&gt;2. The Solution: Formatting a 25M-line Codebase
&lt;/h2&gt;&lt;p&gt;The most impressive part of the article was &lt;strong&gt;&amp;ldquo;Formatting a 25M-line codebase overnight.&amp;rdquo;&lt;/strong&gt; The process of formatting and refactoring 25 million lines of code required more than just technical challenges; it demanded strategy akin to chess.&lt;/p&gt;
&lt;h3 id="21-preparations-for-refactoring"&gt;2.1. Preparations for Refactoring
&lt;/h3&gt;&lt;p&gt;The biggest fear in large-scale refactoring is &lt;strong&gt;&amp;ldquo;regression.&amp;rdquo;&lt;/strong&gt; Modifying the array structure could affect hundreds of Redis commands (like &lt;code&gt;LPUSH&lt;/code&gt;, &lt;code&gt;RPUSH&lt;/code&gt;, &lt;code&gt;LINDEX&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;p&gt;To mitigate this, the team adopted the following approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Expand Test Coverage:&lt;/strong&gt; Ensure existing commands pass unit tests.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strengthen CI/CD Pipeline:&lt;/strong&gt; Implement benchmarking scripts to immediately detect performance degradation upon code changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="22-the-new-structure-of-redis-arrays"&gt;2.2. The New Structure of Redis Arrays
&lt;/h3&gt;&lt;p&gt;The improved Array structure moved beyond simply allocating memory and was modified to maximize data locality. The core principle was &lt;strong&gt;&amp;ldquo;maximizing the use of contiguous memory blocks while allowing for segmentation and management when necessary.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This yielded the following benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Improved CPU Cache Hit Rate:&lt;/strong&gt; Significantly increased L1/L2 cache hit rates due to contiguous memory access.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory Savings:&lt;/strong&gt; Reduced actual data storage space by minimizing unnecessary pointer connections.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-practical-guide-efficient-array-usage-in-redis"&gt;3. Practical Guide: Efficient Array Usage in Redis
&lt;/h2&gt;&lt;p&gt;Now that we&amp;rsquo;ve covered the theoretical background, let&amp;rsquo;s look at how to apply it in practice with code.&lt;/p&gt;
&lt;h3 id="31-problems-with-existing-list-usage"&gt;3.1. Problems with Existing List Usage
&lt;/h3&gt;&lt;p&gt;First, let&amp;rsquo;s consider the traditional way of adding tens of millions of items to a list. This operates based on &lt;code&gt;QuickList&lt;/code&gt;, and as the number of items increases, the number of jumps also increases.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Traditional Method (QuickList based)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Add 10,000,000 items (potential for memory and speed degradation)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i in &lt;span style="color:#f92672"&gt;{&lt;/span&gt;1..10000000&lt;span style="color:#f92672"&gt;}&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; redis-cli LPUSH my_huge_list &lt;span style="color:#e6db74"&gt;&amp;#34;item:&lt;/span&gt;$i&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="32-optimization-using-streams-and-hashes"&gt;3.2. Optimization using Streams and Hashes
&lt;/h3&gt;&lt;p&gt;While the internal improvements to Redis Arrays are transparent to users, when designing, we need to consider &lt;strong&gt;&amp;ldquo;data size&amp;rdquo;&lt;/strong&gt; and &lt;strong&gt;&amp;ldquo;access patterns.&amp;rdquo;&lt;/strong&gt; If simple sequential storage is all that&amp;rsquo;s needed, using the latest version of Redis alone will provide benefits.&lt;/p&gt;
&lt;p&gt;However, if you need to search or modify data within the array, it&amp;rsquo;s advisable to use &lt;code&gt;HASH&lt;/code&gt; instead of &lt;code&gt;LIST&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; redis
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;r &lt;span style="color:#f92672"&gt;=&lt;/span&gt; redis&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Redis(host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;, port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6379&lt;/span&gt;, db&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Scenario: Storing Log Data (Large Scale)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1. Using List (for sequential storage)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;push_to_list&lt;/span&gt;(count):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(count):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lpush(&lt;span style="color:#e6db74"&gt;&amp;#34;logs:timeline&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log_entry_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;i&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;List pushed &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;count&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; items in &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.4f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;s&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 2. Using Hash (for search and modification)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;push_to_hash&lt;/span&gt;(count):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; start &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pipe &lt;span style="color:#f92672"&gt;=&lt;/span&gt; r&lt;span style="color:#f92672"&gt;.&lt;/span&gt;pipeline()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(count):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pipe&lt;span style="color:#f92672"&gt;.&lt;/span&gt;hset(&lt;span style="color:#e6db74"&gt;&amp;#34;logs:details&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;entry_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;i&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;log_content_&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;i&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pipe&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Hash pushed &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;count&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt; items in &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;time() &lt;span style="color:#f92672"&gt;-&lt;/span&gt; start&lt;span style="color:#e6db74"&gt;:&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.4f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;s&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; __name__ &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Test inserting 100,000 data points&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; push_to_list(&lt;span style="color:#ae81ff"&gt;100000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; push_to_hash(&lt;span style="color:#ae81ff"&gt;100000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Execution Result Analysis:&lt;/strong&gt;
In recent Redis versions (7.x and above), the internal Array structure is optimized, making &lt;code&gt;LPUSH&lt;/code&gt; very fast. However, if you frequently need to retrieve data at a specific index, &lt;code&gt;LINDEX&lt;/code&gt; has a complexity of O(N), making the O(1) approach using &lt;code&gt;HGET&lt;/code&gt; much more advantageous.&lt;/p&gt;
&lt;h2 id="4-conclusion-the-harmony-of-development-culture-and-technology"&gt;4. Conclusion: The Harmony of Development Culture and Technology
&lt;/h2&gt;&lt;p&gt;The development process of Redis Arrays offers us important lessons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Performance Isn&amp;rsquo;t Free:&lt;/strong&gt; Improving 25-year-old code requires commensurate refactoring and testing costs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Investment in Tools:&lt;/strong&gt; This work was possible due to automated tools and a CI/CD environment capable of formatting 25 million lines of code.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When we design systems, we need to go beyond simply asking &amp;ldquo;Is it fast?&amp;rdquo; and consider &amp;ldquo;How can we achieve maintainable performance?&amp;rdquo; As the Redis team demonstrated, sometimes we must not shy away from large-scale improvements that shake the foundations of the architecture.&lt;/p&gt;
&lt;h2 id="5-references"&gt;5. References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://news.ycombinator.com/item?id=41284521" target="_blank" rel="noopener"
 &gt;Formatting a 25M-line codebase overnight (Hacker News)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://redis.io/docs/data-types/lists/" target="_blank" rel="noopener"
 &gt;Redis Internals: QuickList&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>AgentForge Blog Automation Service: Full Architecture - From AI Comments to Translation and Post Generation</title><link>https://blog.agentthread.dev/post/2026-05-05-001-agentforge-blog-automation-architecture/</link><pubDate>Tue, 05 May 2026 00:30:00 +0900</pubDate><guid>https://blog.agentthread.dev/post/2026-05-05-001-agentforge-blog-automation-architecture/</guid><description>&lt;p&gt;Running a blog involves three of the most tedious tasks: replying to comments, maintaining English translations, and consistently writing new posts. The &lt;a class="link" href="https://github.com/yarang" target="_blank" rel="noopener"
 &gt;AgentForge&lt;/a&gt; project automates all three with AI agents.&lt;/p&gt;
&lt;p&gt;This post outlines the complete architecture of our blog automation service, which operates across two servers.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="system-topology"&gt;System Topology
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────┐ HTTPS ┌─────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ arm1 server │ ──────────────▶ │ ec1 server │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ (Agent Operator) │ │ (Blog Hosting) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────┤ ├─────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ blog-agent (:8081) │ │ Hugo (nginx) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├─ CommentHandler │ │ Blog API (:8000) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├─ TranslateHandler│ │ ├─ translator.py │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └─ PostGenerator │ │ ├─ blog_manager.py │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ │ └─ git_handler.py │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ NATS / PostgreSQL │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Prometheus / Grafana │ │ Git (yarang/blogs) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────┘ └─────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Server&lt;/th&gt;
					&lt;th&gt;Role&lt;/th&gt;
					&lt;th&gt;Core Services&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;arm1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Agent Operator&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;blog-agent.service&lt;/code&gt; — Flask + Scheduler + LLM Client&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ec1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Blog Hosting + API&lt;/td&gt;
					&lt;td&gt;Hugo (nginx) + &lt;code&gt;blog-api.service&lt;/code&gt; (FastAPI)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Communication between the two servers is restricted to &lt;strong&gt;HTTPS API calls only&lt;/strong&gt;. SSH access from arm1 to ec1 is blocked, so all integrations are done through the Blog API.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="arm1-unified-blog-agent"&gt;arm1: Unified Blog Agent
&lt;/h2&gt;&lt;h3 id="why-unified"&gt;Why Unified?
&lt;/h3&gt;&lt;p&gt;Initially, comment response, translation, and post generation operated as separate processes (three systemd services). The issues were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using Claude Code CLI (&lt;code&gt;--print&lt;/code&gt;) for calls resulted in a &lt;strong&gt;response time of 9.7 seconds&lt;/strong&gt; and consumed 688MB of disk space.&lt;/li&gt;
&lt;li&gt;Managing six systemd units was burdensome.&lt;/li&gt;
&lt;li&gt;No state sharing between processes was possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By unifying these into &lt;strong&gt;one process&lt;/strong&gt; and switching to direct LLM API calls, we achieved the following:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Metric&lt;/th&gt;
					&lt;th&gt;Before&lt;/th&gt;
					&lt;th&gt;After&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Response Time&lt;/td&gt;
					&lt;td&gt;9.7s&lt;/td&gt;
					&lt;td&gt;1.7s&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Disk Usage&lt;/td&gt;
					&lt;td&gt;688MB&lt;/td&gt;
					&lt;td&gt;~50MB&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;systemd Units&lt;/td&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Processes&lt;/td&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="architecture"&gt;Architecture
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BlogAgent&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;1 Process = Flask (webhook) + Scheduler (timer) + LLM Client&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config &lt;span style="color:#f92672"&gt;=&lt;/span&gt; AgentConfig&lt;span style="color:#f92672"&gt;.&lt;/span&gt;from_credentials()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;llm &lt;span style="color:#f92672"&gt;=&lt;/span&gt; LLMClient(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config) &lt;span style="color:#75715e"&gt;# ZAI glm-4.7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;api &lt;span style="color:#f92672"&gt;=&lt;/span&gt; BlogAPIClient(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config) &lt;span style="color:#75715e"&gt;# ec1 Blog API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Handlers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;comment &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CommentHandler(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;llm, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;config)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;translate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; TranslateHandler(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;api)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;post_gen &lt;span style="color:#f92672"&gt;=&lt;/span&gt; PostGenerator(self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;llm, self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;api)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Scheduler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;scheduler &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Scheduler()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;scheduler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;every(hours&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;, task&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;translate&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_and_sync)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;scheduler&lt;span style="color:#f92672"&gt;.&lt;/span&gt;daily_at(hour&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;, task&lt;span style="color:#f92672"&gt;=&lt;/span&gt;self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;post_gen&lt;span style="color:#f92672"&gt;.&lt;/span&gt;generate_and_publish)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="module-operations"&gt;Module Operations
&lt;/h3&gt;&lt;h4 id="1-commenthandler--ai-comment-response"&gt;1. CommentHandler — AI Comment Response
&lt;/h4&gt;&lt;p&gt;Receives Webhook events from GitHub Discussions to automatically generate AI comments.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[User Comment] → GitHub Webhook → arm1 Flask → CommentHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; → LLM Call (ZAI glm-4.7) → Generate Reply → Post Comment via GitHub API
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trigger&lt;/strong&gt;: Webhook event-based (real-time)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filtering&lt;/strong&gt;: Skips blog owner comments and AI-generated comments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: HMAC-SHA256 Webhook secret verification, Flask-Limiter applied.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-translatehandler--automatic-translation-trigger"&gt;2. TranslateHandler — Automatic Translation Trigger
&lt;/h4&gt;&lt;p&gt;Requests translation synchronization from ec1&amp;rsquo;s Blog API every 6 hours.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Scheduler 6h] → TranslateHandler.check_and_sync()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; → POST /translate/sync → ec1 Blog API performs actual translation
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;arm1 does not perform the translation itself; it only sends a &lt;strong&gt;trigger&lt;/strong&gt; to the ec1 API. The actual translation logic resides in &lt;code&gt;translator.py&lt;/code&gt; on ec1.&lt;/p&gt;
&lt;h4 id="3-postgenerator--automatic-post-generation"&gt;3. PostGenerator — Automatic Post Generation
&lt;/h4&gt;&lt;p&gt;Automatically generates technical blog posts every day at 9 AM.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Scheduler 09:00 KST] → PostGenerator.generate_and_publish()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; → Collect existing topics → Refer to RSS trends → Generate content with LLM
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; → Deduplication Check → Publish via Blog API
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Deduplication&lt;/strong&gt; is key. It compares the similarity between new titles and the last 100 existing titles using &lt;code&gt;difflib.SequenceMatcher&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_is_duplicate_title&lt;/span&gt;(self, new_title, existing_titles):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Considers it a duplicate if the ratio is &amp;gt;= 0.6&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; new_lower &lt;span style="color:#f92672"&gt;=&lt;/span&gt; new_title&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lower()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; title &lt;span style="color:#f92672"&gt;in&lt;/span&gt; existing_titles[&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;:]:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ex_lower &lt;span style="color:#f92672"&gt;=&lt;/span&gt; title&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lower()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ratio &lt;span style="color:#f92672"&gt;=&lt;/span&gt; difflib&lt;span style="color:#f92672"&gt;.&lt;/span&gt;SequenceMatcher(&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;, new_lower, ex_lower)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ratio()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ratio &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0.6&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="ec1-blog-api-translation-system"&gt;ec1: Blog API Translation System
&lt;/h2&gt;&lt;h3 id="transition-to-gemini"&gt;Transition to Gemini
&lt;/h3&gt;&lt;p&gt;Initially, translations were performed using ZAI (glm-4.7), but a critical issue arose:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;glm-4.7 is a &lt;strong&gt;reasoning model&lt;/strong&gt;, which first consumes its &lt;code&gt;max_tokens&lt;/code&gt; budget for &lt;code&gt;reasoning_content&lt;/code&gt; (internal thought process). If &lt;code&gt;max_tokens=256&lt;/code&gt;, it uses all 256 tokens for reasoning, leaving the actual &lt;code&gt;content&lt;/code&gt; as an empty string.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;This led to an incident where &lt;strong&gt;nine English posts were translated with empty string titles&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Solution: Replaced with &lt;strong&gt;Gemini 2.5 Flash Lite&lt;/strong&gt;.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Item&lt;/th&gt;
					&lt;th&gt;ZAI (Previous)&lt;/th&gt;
					&lt;th&gt;Gemini (Current)&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Model&lt;/td&gt;
					&lt;td&gt;glm-4.7 (reasoning)&lt;/td&gt;
					&lt;td&gt;gemini-2.5-flash-lite&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Translation Time&lt;/td&gt;
					&lt;td&gt;~30s/post&lt;/td&gt;
					&lt;td&gt;~8s/post&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Cost&lt;/td&gt;
					&lt;td&gt;Paid API&lt;/td&gt;
					&lt;td&gt;Free (1,500 requests/day)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Empty Response Issue&lt;/td&gt;
					&lt;td&gt;Occurred&lt;/td&gt;
					&lt;td&gt;None&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="openai-compatible-endpoint"&gt;OpenAI-Compatible Endpoint
&lt;/h3&gt;&lt;p&gt;Gemini provides an OpenAI-compatible API. The existing code can be used &lt;strong&gt;without any changes&lt;/strong&gt; by simply switching the base URL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;LLM_BASE_URLS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;GEMINI&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://generativelanguage.googleapis.com/v1beta/openai&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ZAI&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://api.z.ai/api/coding/paas/v4&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="translation-matching-logic"&gt;Translation Matching Logic
&lt;/h3&gt;&lt;p&gt;Pairing Korean↔English posts uses &lt;strong&gt;date prefix matching&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ko: 2026-05-04-001-개발-생산성-17배-극대화-deepseek-v4와-...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;en: 2026-05-04-001-개발-생산성-17배-극대화-deepseek-v4와-...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ↑ Same prefix = Same post
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although the slugs might differ in language, if the &lt;code&gt;YYYY-MM-DD-NNN&lt;/code&gt; part is the same, it&amp;rsquo;s recognized as the same post. The prerequisite for this method is that &lt;strong&gt;no two posts with the same date and number exist&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="title-in-body-translation-technique"&gt;Title-in-Body Translation Technique
&lt;/h3&gt;&lt;p&gt;Translating the title via a separate API call caused issues with empty results from the reasoning model. The solution is to &lt;strong&gt;include the title as the first line of the body&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# When requesting translation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;prompt &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;# &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;original_title&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;original_body&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Extracting the title from the translation result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; translated&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lstrip()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;startswith(&lt;span style="color:#e6db74"&gt;&amp;#34;# &amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lines &lt;span style="color:#f92672"&gt;=&lt;/span&gt; translated&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lstrip()&lt;span style="color:#f92672"&gt;.&lt;/span&gt;split(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; extracted_title &lt;span style="color:#f92672"&gt;=&lt;/span&gt; lines[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lstrip(&lt;span style="color:#e6db74"&gt;&amp;#34;# &amp;#34;&lt;/span&gt;)&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; translated_body &lt;span style="color:#f92672"&gt;=&lt;/span&gt; lines[&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;lstrip(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This translates the title and body simultaneously in a single API call, preserving context and saving tokens.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="llm-strategy-role-based-model-separation"&gt;LLM Strategy: Role-Based Model Separation
&lt;/h2&gt;&lt;p&gt;Not all tasks are handled by a single LLM. Models are separated based on the nature of the task.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Task&lt;/th&gt;
					&lt;th&gt;Server&lt;/th&gt;
					&lt;th&gt;Model&lt;/th&gt;
					&lt;th&gt;Reason&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;AI Comment Response&lt;/td&gt;
					&lt;td&gt;arm1&lt;/td&gt;
					&lt;td&gt;ZAI glm-4.7&lt;/td&gt;
					&lt;td&gt;Conversational, excellent Korean quality&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Post Generation&lt;/td&gt;
					&lt;td&gt;arm1&lt;/td&gt;
					&lt;td&gt;ZAI glm-4.7&lt;/td&gt;
					&lt;td&gt;Long-form content generation, creativity required&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Translation (ko→en)&lt;/td&gt;
					&lt;td&gt;ec1&lt;/td&gt;
					&lt;td&gt;Gemini Flash Lite&lt;/td&gt;
					&lt;td&gt;Non-reasoning, fast and free&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Core Principle: &lt;strong&gt;Do not use reasoning models for translation&lt;/strong&gt;. Reasoning models consume tokens for internal thought processes, making non-reasoning models more suitable for simple conversion tasks.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="monitoring-and-operations"&gt;Monitoring and Operations
&lt;/h2&gt;&lt;h3 id="health-check-endpoints"&gt;Health Check Endpoints
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# arm1 agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl http://arm1:8081/health
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# → {&amp;#34;status&amp;#34;:&amp;#34;healthy&amp;#34;,&amp;#34;agent&amp;#34;:&amp;#34;blog-agent&amp;#34;,&amp;#34;scheduler_jobs&amp;#34;:2,&amp;#34;uptime_sec&amp;#34;:...}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl http://arm1:8081/status
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# → {&amp;#34;scheduler&amp;#34;:[{&amp;#34;name&amp;#34;:&amp;#34;auto-translate&amp;#34;,&amp;#34;last_run&amp;#34;:...},{&amp;#34;name&amp;#34;:&amp;#34;post-generator&amp;#34;,&amp;#34;last_run&amp;#34;:&amp;#34;2026-05-04&amp;#34;}]}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ec1 Blog API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl https://blog.example.com/api/health
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# → {&amp;#34;status&amp;#34;:&amp;#34;healthy&amp;#34;,&amp;#34;version&amp;#34;:&amp;#34;2.0.0&amp;#34;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="observability-points"&gt;Observability Points
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Metric&lt;/th&gt;
					&lt;th&gt;Normal Range&lt;/th&gt;
					&lt;th&gt;Alert Condition&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;arm1 uptime&lt;/td&gt;
					&lt;td&gt;&amp;gt;0&lt;/td&gt;
					&lt;td&gt;Service Down&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;scheduler_jobs&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;≠ 2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Translation Sync&lt;/td&gt;
					&lt;td&gt;ko post count = en post count&lt;/td&gt;
					&lt;td&gt;Discrepancy occurs&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Post Generation&lt;/td&gt;
					&lt;td&gt;1 post daily&lt;/td&gt;
					&lt;td&gt;No posts for over 24 hours&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="lessons-learned-and-operational-tips"&gt;Lessons Learned and Operational Tips
&lt;/h2&gt;&lt;h3 id="1-the-pitfall-of-reasoning-models"&gt;1. The Pitfall of Reasoning Models
&lt;/h3&gt;&lt;p&gt;It&amp;rsquo;s often not explicitly stated in documentation that &lt;code&gt;max_tokens&lt;/code&gt; &lt;strong&gt;combines&lt;/strong&gt; reasoning and content. If you get an empty response, check the &lt;code&gt;finish_reason&lt;/code&gt;—if it&amp;rsquo;s &lt;code&gt;&amp;quot;length&amp;quot;&lt;/code&gt;, it indicates insufficient token budget.&lt;/p&gt;
&lt;h3 id="2-value-of-the-openai-compatible-pattern"&gt;2. Value of the OpenAI-Compatible Pattern
&lt;/h3&gt;&lt;p&gt;When switching translation providers from ZAI to Gemini, the code change was just &lt;strong&gt;one line for the base URL&lt;/strong&gt;. Abstracting to an OpenAI-compatible interface from the start dramatically reduces LLM replacement costs.&lt;/p&gt;
&lt;h3 id="3-constraints-of-date-prefix-matching"&gt;3. Constraints of Date Prefix Matching
&lt;/h3&gt;&lt;p&gt;In the &lt;code&gt;YYYY-MM-DD-NNN&lt;/code&gt; pattern, if two or more posts share the same date and number, translation matching will break. The &lt;code&gt;PostGenerator&lt;/code&gt; must include logic to check the last number for that date and increment it when generating new posts.&lt;/p&gt;
&lt;h3 id="4-benefits-of-process-consolidation"&gt;4. Benefits of Process Consolidation
&lt;/h3&gt;&lt;p&gt;Consolidating three independent services into one resulted in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;State Sharing (LLM clients, configurations, API clients initialized only once)&lt;/li&gt;
&lt;li&gt;Simplified Deployment (one systemd unit)&lt;/li&gt;
&lt;li&gt;Easier Debugging (logs consolidated in one place)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="future-plans"&gt;Future Plans
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Review the integration of arm1 agent&amp;rsquo;s LLM with Gemini.&lt;/li&gt;
&lt;li&gt;Comment Quality Evaluation Pipeline (monitoring the appropriateness of auto-generated comments).&lt;/li&gt;
&lt;li&gt;Automatic Translation Quality Verification (comparing with back-translation).&lt;/li&gt;
&lt;li&gt;Expanding inter-agent collaboration through the AgentForge framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Blog automation aims not for &amp;ldquo;complete automation,&amp;rdquo; but for &amp;ldquo;minimal human intervention.&amp;rdquo; A structure where AI generates content, humans review it, and the system alerts operators to anomalies is the key to stable operation.&lt;/p&gt;</description></item><item><title>[Discord Decision MCP] Architecture Design Document</title><link>https://blog.agentthread.dev/post/discord-decision-mcp-architecture-design-v2/</link><pubDate>Mon, 02 Mar 2026 21:36:30 +0900</pubDate><guid>https://blog.agentthread.dev/post/discord-decision-mcp-architecture-design-v2/</guid><description>&lt;h1 id="discord-decision-mcp--architecture-design-document"&gt;Discord Decision MCP — Architecture Design Document
&lt;/h1&gt;&lt;h2 id="1-project-overview"&gt;1. Project Overview
&lt;/h2&gt;&lt;h3 id="11-purpose"&gt;1.1 Purpose
&lt;/h3&gt;&lt;p&gt;An MCP (Model Context Protocol) server that allows Claude Code, while operating in tmux Teammate mode for autonomous work, to ask questions via Discord when user decisions are needed and resume work after receiving responses.&lt;/p&gt;
&lt;h3 id="12-key-features"&gt;1.2 Key Features
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Feature&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;One Bot per Project&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Each project uses an independent Discord Bot&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Infinite Wait Default&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Wait for user response without timeout (Claude must not proceed unilaterally)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;State Persistence&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Restore waiting state after process restart&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Korean-Friendly&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Korean options, Yes/No response support&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;MCP-Based Communication&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;All Discord communication through MCP Tools&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="13-version-information"&gt;1.3 Version Information
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version&lt;/strong&gt;: 1.0.0&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python Requirement&lt;/strong&gt;: &amp;gt;= 3.11&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP Framework&lt;/strong&gt;: FastMCP &amp;gt;= 0.1.0&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="2-directory-structure"&gt;2. Directory Structure
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;discord&lt;span style="color:#f92672"&gt;-&lt;/span&gt;decision&lt;span style="color:#f92672"&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; discord_mcp&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Main package&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; __init__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; server&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# MCP server entry point&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; config&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# Environment variable configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; bot&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Discord API client&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; __init__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; client&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# REST API client (httpx)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; gateway&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# WebSocket gateway (receive only)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; decision&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Decision request management&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; __init__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; manager&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# Decision request lifecycle management&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; poller&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# Discord polling and response waiting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# User response parsing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; state&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# State persistence (JSON files)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; tools&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# MCP Tools implementation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; __init__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; ask&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# discord_ask_decision&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; notify&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# discord_notify&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; report&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# discord_report_progress&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; status&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# discord_check_pending&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; inbox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# discord_read_inbox, discord_clear_inbox&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; _templates&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# Discord message templates&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; daemon&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Watcher daemon&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; __init__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; watcher&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# Discord channel monitoring (discord-watch CLI)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; inbox&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py &lt;span style="color:#75715e"&gt;# Inbox file management&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; scripts&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Utility scripts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; start&lt;span style="color:#f92672"&gt;-&lt;/span&gt;discord&lt;span style="color:#f92672"&gt;-&lt;/span&gt;watch&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sh
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; tests&lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Test suite&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; __init__&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; test_parser&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; test_state&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; CLAUDE&lt;span style="color:#f92672"&gt;.&lt;/span&gt;md &lt;span style="color:#75715e"&gt;# Claude Code project instructions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; README&lt;span style="color:#f92672"&gt;.&lt;/span&gt;md &lt;span style="color:#75715e"&gt;# Project description&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;├──&lt;/span&gt; pyproject&lt;span style="color:#f92672"&gt;.&lt;/span&gt;toml &lt;span style="color:#75715e"&gt;# Project configuration and dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;└──&lt;/span&gt; mcp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;json&lt;span style="color:#f92672"&gt;.&lt;/span&gt;example &lt;span style="color:#75715e"&gt;# MCP configuration example&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="3-key-module-descriptions"&gt;3. Key Module Descriptions
&lt;/h2&gt;&lt;h3 id="31-server-entry-point-serverpy"&gt;3.1 Server Entry Point (&lt;code&gt;server.py&lt;/code&gt;)
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: FastMCP server creation and MCP Tool registration&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FastMCP(name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;discord-decision-mcp&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Tool registration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tool()(discord_ask_decision)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tool()(discord_notify)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tool()(discord_report_progress)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tool()(discord_check_pending)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tool()(discord_read_inbox)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp&lt;span style="color:#f92672"&gt;.&lt;/span&gt;tool()(discord_clear_inbox)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Execution&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;discord-mcp &lt;span style="color:#75715e"&gt;# or python -m discord_mcp.server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="32-configuration-management-configpy"&gt;3.2 Configuration Management (&lt;code&gt;config.py&lt;/code&gt;)
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: Load configuration values from environment variables&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Environment Variable&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DISCORD_BOT_TOKEN&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Discord Bot Token (includes &amp;ldquo;Bot &amp;quot; prefix)&lt;/td&gt;
					&lt;td&gt;Required&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DISCORD_CHANNEL_ID&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Default question channel ID&lt;/td&gt;
					&lt;td&gt;Required&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;PROJECT_NAME&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Used for question_id generation&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;project&amp;rdquo;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;PENDING_DIR&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;State file storage path&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;~/.claude/pending_decisions&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;POLL_INTERVAL_SECONDS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Discord polling interval (seconds)&lt;/td&gt;
					&lt;td&gt;5&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="33-discord-api-client-bot"&gt;3.3 Discord API Client (&lt;code&gt;bot/&lt;/code&gt;)
&lt;/h3&gt;&lt;h4 id="331-rest-api-client-clientpy"&gt;3.3.1 REST API Client (&lt;code&gt;client.py&lt;/code&gt;)
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: Discord REST API calls (httpx-based)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Methods&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DiscordClient&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send_message&lt;/span&gt;(channel_id, content, embeds&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_messages&lt;/span&gt;(channel_id, after&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;, limit&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;create_thread&lt;/span&gt;(channel_id, name, first_message)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;archive_thread&lt;/span&gt;(thread_id)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Automatic rate limit handling (retry on 429 response)&lt;/li&gt;
&lt;li&gt;Singleton pattern (&lt;code&gt;get_client()&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="332-websocket-gateway-gatewaypy"&gt;3.3.2 WebSocket Gateway (&lt;code&gt;gateway.py&lt;/code&gt;)
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: Discord Gateway WebSocket connection (receive only)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real-time MESSAGE_CREATE event reception&lt;/li&gt;
&lt;li&gt;Reduces polling delay from 5 seconds to instant&lt;/li&gt;
&lt;li&gt;System works without Gateway (polling fallback)&lt;/li&gt;
&lt;li&gt;Automatic reconnection (Exponential backoff)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;GatewayClient&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;() &lt;span style="color:#75715e"&gt;# Start event reception&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stop&lt;/span&gt;() &lt;span style="color:#75715e"&gt;# Close connection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="34-decision-request-management-decision"&gt;3.4 Decision Request Management (&lt;code&gt;decision/&lt;/code&gt;)
&lt;/h3&gt;&lt;h4 id="341-decisionmanager-managerpy"&gt;3.4.1 DecisionManager (&lt;code&gt;manager.py&lt;/code&gt;)
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: Coordinate the entire lifecycle of decision requests&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DecisionManager&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ask&lt;/span&gt;(question, context, options, timeout_seconds, thread_id) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; PollResult
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;restore_pending&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; list[DecisionState]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Flow&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check for duplicate questions&lt;/li&gt;
&lt;li&gt;Create thread (or reuse existing thread)&lt;/li&gt;
&lt;li&gt;Create state file (&lt;code&gt;~/.claude/pending_decisions/{question_id}.json&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Run poller to wait for response&lt;/li&gt;
&lt;li&gt;Mark disconnected state on SIGHUP signal&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="342-decisionpoller-pollerpy"&gt;3.4.2 DecisionPoller (&lt;code&gt;poller.py&lt;/code&gt;)
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: Poll Discord channel and wait for response&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DecisionPoller&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;wait&lt;/span&gt;(state: DecisionState) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; PollResult
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Default: infinite wait (&lt;code&gt;timeout_seconds=None&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Real-time waiting status display in tmux pane (ANSI escape)&lt;/li&gt;
&lt;li&gt;Re-question up to 2 times for ambiguous responses&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="343-response-parser-parserpy"&gt;3.4.3 Response Parser (&lt;code&gt;parser.py&lt;/code&gt;)
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: Parse user Discord responses&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supported Patterns&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Option matching: &amp;ldquo;A&amp;rdquo;, &amp;ldquo;a&amp;rdquo;, &amp;ldquo;A번&amp;rdquo;, &amp;ldquo;A로 해줘&amp;rdquo;, &amp;ldquo;1&amp;rdquo;, &amp;ldquo;1번&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Affirmative/Negative: &amp;ldquo;yes&amp;rdquo;, &amp;ldquo;네&amp;rdquo;, &amp;ldquo;예&amp;rdquo;, &amp;ldquo;no&amp;rdquo;, &amp;ldquo;아니요&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Natural language: 15+ characters or 3+ Korean characters&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;parse_response&lt;/span&gt;(text: str, options: list[str]) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; ParseResult
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;build_clarify_message&lt;/span&gt;(&lt;span style="color:#f92672"&gt;...&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; str &lt;span style="color:#75715e"&gt;# Generate re-question message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="344-state-store-statepy"&gt;3.4.4 State Store (&lt;code&gt;state.py&lt;/code&gt;)
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: Persist decision request state to JSON files&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;State File Location&lt;/strong&gt;: &lt;code&gt;~/.claude/pending_decisions/{question_id}.json&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DecisionState&lt;/span&gt;(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; question_id: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; project: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; question: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; context: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options: list[str]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout_seconds: float &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; thread_id: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message_id: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; asked_at: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; status: Literal[&lt;span style="color:#e6db74"&gt;&amp;#34;pending&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;disconnected&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;resolved&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;aborted&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;timeout&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; clarify_attempts: int
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resolved_at: str &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resolution: str &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; selected_option: str &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StateStore&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;save&lt;/span&gt;(state: DecisionState)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;load&lt;/span&gt;(question_id: str) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; DecisionState &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;load_all_pending&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; list[DecisionState]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;resolve&lt;/span&gt;(question_id, resolution, selected_option)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is_duplicate&lt;/span&gt;(question: str) &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; bool
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="35-mcp-tools-tools"&gt;3.5 MCP Tools (&lt;code&gt;tools/&lt;/code&gt;)
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Tool&lt;/th&gt;
					&lt;th&gt;Blocking&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;discord_ask_decision&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;User decision request&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;discord_notify&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Progress notification&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;discord_report_progress&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Task completion report&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;discord_check_pending&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Check pending questions&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;discord_read_inbox&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Inbox message query&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;discord_clear_inbox&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Inbox message deletion&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="36-watcher-daemon-daemon"&gt;3.6 Watcher Daemon (&lt;code&gt;daemon/&lt;/code&gt;)
&lt;/h3&gt;&lt;h4 id="361-discordwatcher-watcherpy"&gt;3.6.1 DiscordWatcher (&lt;code&gt;watcher.py&lt;/code&gt;)
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: Monitor Discord channel and record new messages to inbox file&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Execution&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;discord-watch --interval &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;tmux new-session -d -s discord-watch &lt;span style="color:#e6db74"&gt;&amp;#39;uv run discord-watch&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Periodically poll specified channel(s)&lt;/li&gt;
&lt;li&gt;Record new user messages to inbox&lt;/li&gt;
&lt;li&gt;Display status in tmux pane&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="362-inboxstore-inboxpy"&gt;3.6.2 InboxStore (&lt;code&gt;inbox.py&lt;/code&gt;)
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Role&lt;/strong&gt;: JSON file-based storage for Discord messages&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inbox File Location&lt;/strong&gt;: &lt;code&gt;~/.claude/discord_inbox.json&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;InboxMessage&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message_id: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; channel_id: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; thread_id: str &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; author: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; author_id: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; content: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timestamp: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; read: bool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;InboxStore&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add_message&lt;/span&gt;(msg: InboxMessage)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_unread&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; list[InboxMessage]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mark_read&lt;/span&gt;(message_id: str)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;clear_read&lt;/span&gt;() &lt;span style="color:#75715e"&gt;# Delete read messages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="4-data-flow-diagrams"&gt;4. Data Flow Diagrams
&lt;/h2&gt;&lt;h3 id="41-decision-request-flow"&gt;4.1 Decision Request Flow
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Claude Code │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└────────┬────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ discord_ask_decision()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ MCP Server (server.py) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌───────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ DecisionManager.ask() │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 1. Duplicate check │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 2. Thread creation │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 3. State file save │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └───────────────┬───────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└──────────────────┼──────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ DecisionPoller.wait() │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌───────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ Polling loop │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 1. tmux status update │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 2. Discord API call │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 3. Response parsing │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 4. Re-question if ambiguous │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └───────────────┬───────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└──────────────────┼──────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ┌─────────┴─────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼ ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌───────────────────┐ ┌──────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Discord REST API │ │ Discord Thread │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ (client.py) │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└───────────────────┘ └────────┬─────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ┌────────▼────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ User Response │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └────────┬────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ┌─────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ parser.py │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ - Option match │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ - Ambiguity │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └────────┬────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ┌─────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ store.resolve()│
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └────────┬────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ┌─────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ PollResult │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ Return │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └─────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="42-watcher-daemon-flow"&gt;4.2 Watcher Daemon Flow
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ DiscordWatcher (daemon/watcher.py) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌───────────────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 1. Set initial message ID │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 2. Periodic polling (default 10s) │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 3. Detect new messages │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 4. InboxStore.add_message() │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └───────────────────┬───────────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└──────────────────────┼──────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ~/.claude/discord_inbox.json │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ { │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ &amp;#34;last_message_id&amp;#34;: &amp;#34;...&amp;#34;, │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ &amp;#34;messages&amp;#34;: [ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ { &amp;#34;message_id&amp;#34;: &amp;#34;...&amp;#34;, ... } │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ] │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ } │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└──────────────────────┬──────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▲
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; │ discord_read_inbox()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌──────────────────────┴──────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Claude Code │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="43-session-restoration-flow"&gt;4.3 Session Restoration Flow
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Claude Code session start │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└──────────────────────┬──────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ discord_check_pending() │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└──────────────────────┬──────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ DecisionManager.restore_pending() │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ┌───────────────────────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 1. ~/.claude/pending_decisions/*.json │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 2. Check Thread via Discord API │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 3. If answered → Auto-resolve │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ 4. If no answer → Restart notification│ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └───────────────────────────────────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="5-mcp-tools-list"&gt;5. MCP Tools List
&lt;/h2&gt;&lt;h3 id="51-discord_ask_decision"&gt;5.1 discord_ask_decision
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Send question to Discord Thread and wait for response when user decision is needed (blocking)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Name&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Required&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;question&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;Question content&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;context&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;Current work context&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;options&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string[]&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;List of options (empty array for free response)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;timeout_seconds&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;float&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Wait timeout (null for infinite wait)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;thread_id&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Existing Thread ID (null to create new Thread)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Return Value&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;answer&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;A) Execute now&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;selected_option&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;A) Execute now&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;question_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;project_20260301_abc123&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;timed_out&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;aborted&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="52-discord_notify"&gt;5.2 discord_notify
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Send progress notification to Discord (non-blocking)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Name&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Required&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;message&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;Notification message&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;level&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;info/warning/success/error (default: info)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;thread_id&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Thread ID to send to (null for default channel)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="53-discord_report_progress"&gt;5.3 discord_report_progress
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Report task completion or milestone completion (non-blocking)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Name&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Required&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;Report title&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;summary&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;✅&lt;/td&gt;
					&lt;td&gt;Task result summary&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;details&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string[]&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;List of detail items&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;thread_id&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;string&lt;/td&gt;
					&lt;td&gt;❌&lt;/td&gt;
					&lt;td&gt;Thread ID to send to&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="54-discord_check_pending"&gt;5.4 discord_check_pending
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Check pending questions at session start (non-blocking)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters&lt;/strong&gt;: None&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Return Value&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;has_pending&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;pending_questions&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;question_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;project_20260301_abc123&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;question&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Deploy?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;thread_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;1234567890&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;asked_at&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2026-03-01T10:30:00Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;pending&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="55-discord_read_inbox"&gt;5.5 discord_read_inbox
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Query messages stored in Inbox (non-blocking)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Name&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;unread_only&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;boolean&lt;/td&gt;
					&lt;td&gt;true&lt;/td&gt;
					&lt;td&gt;Return only unread messages&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;mark_read&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;boolean&lt;/td&gt;
					&lt;td&gt;false&lt;/td&gt;
					&lt;td&gt;Mark queried messages as read&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="56-discord_clear_inbox"&gt;5.6 discord_clear_inbox
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Delete Inbox messages (non-blocking)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parameters&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Name&lt;/th&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;read_only&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;boolean&lt;/td&gt;
					&lt;td&gt;true&lt;/td&gt;
					&lt;td&gt;Delete only read messages&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="6-dependency-information"&gt;6. Dependency Information
&lt;/h2&gt;&lt;h3 id="61-core-dependencies"&gt;6.1 Core Dependencies
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Package&lt;/th&gt;
					&lt;th&gt;Version&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;fastmcp&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&amp;gt;= 0.1.0&lt;/td&gt;
					&lt;td&gt;MCP server framework&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;httpx&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&amp;gt;= 0.27.0&lt;/td&gt;
					&lt;td&gt;Async HTTP client&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;websockets&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&amp;gt;= 12.0&lt;/td&gt;
					&lt;td&gt;WebSocket client&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;python-dotenv&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&amp;gt;= 1.0.0&lt;/td&gt;
					&lt;td&gt;Environment variable loading&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;pydantic&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&amp;gt;= 2.0.0&lt;/td&gt;
					&lt;td&gt;Data model validation&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;anyio&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&amp;gt;= 4.0.0&lt;/td&gt;
					&lt;td&gt;Async execution&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="62-development-dependencies"&gt;6.2 Development Dependencies
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Package&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;pytest&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Test framework&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;pytest-asyncio&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Async test support&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;pytest-mock&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Mock support&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;respx&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;httpx mocking&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="63-cli-commands"&gt;6.3 CLI Commands
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;discord-mcp &lt;span style="color:#75715e"&gt;# Run MCP server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;discord-watch &lt;span style="color:#75715e"&gt;# Run watcher daemon&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="7-state-file-format"&gt;7. State File Format
&lt;/h2&gt;&lt;h3 id="71-decision-state-file"&gt;7.1 Decision State File
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;~/.claude/pending_decisions/{question_id}.json&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;question_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;project_20260301_abc123&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;project&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;my-project&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;question&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Run DB migration?&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;context&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;v1→v2 schema change&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;options&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;A) Execute now&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;B) Staging first&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;C) Hold&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;timeout_seconds&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;thread_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;1234567890&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;message_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;0987654321&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;asked_at&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2026-03-01T10:30:00Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;pending&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;clarify_attempts&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;resolved_at&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;resolution&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;selected_option&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="72-inbox-file"&gt;7.2 Inbox File
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: &lt;code&gt;~/.claude/discord_inbox.json&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;last_message_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;1234567890&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;messages&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;message_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;1234567890&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;channel_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;1234567890&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;thread_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;username&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;author_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;1234567890&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Message content&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2026-03-01T00:00:00Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;read&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="8-architecture-principles"&gt;8. Architecture Principles
&lt;/h2&gt;&lt;h3 id="81-design-principles"&gt;8.1 Design Principles
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Singleton Pattern&lt;/strong&gt;: DiscordClient, StateStore, InboxStore are module-level singletons&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Persistence&lt;/strong&gt;: All decision request states are persisted to files&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Infinite Wait Default&lt;/strong&gt;: Timeout default is None so Claude does not proceed unilaterally&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Re-question Limit&lt;/strong&gt;: Ambiguous responses are re-asked up to 2 times&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate Limit Handling&lt;/strong&gt;: Automatic wait and retry on Discord API 429 responses&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="82-error-handling"&gt;8.2 Error Handling
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Situation&lt;/th&gt;
					&lt;th&gt;Handling&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Discord API 429&lt;/td&gt;
					&lt;td&gt;Automatic wait and retry (max 5 times)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;WebSocket disconnection&lt;/td&gt;
					&lt;td&gt;Reconnect with exponential backoff&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Response parsing failure&lt;/td&gt;
					&lt;td&gt;Re-question up to 2 times then abort&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Timeout occurrence&lt;/td&gt;
					&lt;td&gt;Send abort notification and set aborted state&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Session disconnect (SIGHUP)&lt;/td&gt;
					&lt;td&gt;Save as disconnected state&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Document Version: 1.0.0&lt;/em&gt;
&lt;em&gt;Last Modified: 2026-03-02&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Korean Version:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/ko/post/2026-03-02-002-discord-decision-mcp-architecture-design/" &gt;한국어 버전&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[ZeroClaw] 2026 H1 Roadmap Meeting</title><link>https://blog.agentthread.dev/post/2026-02-28-001-zeroclaw-2026-h1-roadmap-meeting/</link><pubDate>Sat, 28 Feb 2026 09:55:15 +0900</pubDate><guid>https://blog.agentthread.dev/post/2026-02-28-001-zeroclaw-2026-h1-roadmap-meeting/</guid><description>&lt;h1 id="zeroclaw-2026-h1-roadmap-team-meeting-minutes"&gt;ZeroClaw 2026 H1 Roadmap Team Meeting Minutes
&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;Meeting Date&lt;/strong&gt;: 2026-02-28
&lt;strong&gt;Attendees&lt;/strong&gt;: Architect, Security Lead, Product Owner, DevOps Lead
&lt;strong&gt;Location&lt;/strong&gt;: ZeroClaw Development Team Meeting Room
&lt;strong&gt;Author&lt;/strong&gt;: ZeroClaw Team&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-meeting-overview"&gt;1. Meeting Overview
&lt;/h2&gt;&lt;p&gt;This meeting was held to discuss ZeroClaw&amp;rsquo;s 2026 first-half development direction and establish roadmaps and priorities for each area.&lt;/p&gt;
&lt;h3 id="11-agenda"&gt;1.1 Agenda
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Multi-agent architecture development direction&lt;/li&gt;
&lt;li&gt;Security enhancement and compliance response&lt;/li&gt;
&lt;li&gt;Product competitiveness enhancement and UX improvement&lt;/li&gt;
&lt;li&gt;DevOps and infrastructure advancement&lt;/li&gt;
&lt;li&gt;Comprehensive roadmap and priority agreement&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="2-architecture-development-discussion"&gt;2. Architecture Development Discussion
&lt;/h2&gt;&lt;h3 id="21-architect-statement"&gt;2.1 Architect Statement
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;ZeroClaw has completed Phase 1 (in-process delegation) and is currently implementing Phase 2 (file-based multi-agent). The following technical goals need to be achieved in the first half of 2026.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="211-multi-agent-orchestration-advancement"&gt;2.1.1 Multi-Agent Orchestration Advancement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement DAG-based workflow execution engine&lt;/li&gt;
&lt;li&gt;Support sequential/parallel/conditional/loop execution patterns&lt;/li&gt;
&lt;li&gt;Improve agent task distribution algorithm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; High (P1)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Proposed workflow structure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Workflow&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; nodes: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;WorkflowNode&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; edges: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;WorkflowEdge&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; start_node: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; end_nodes: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; error_handling: &lt;span style="color:#a6e22e"&gt;ErrorHandlingPolicy&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="212-ipc-communication-protocol-improvement"&gt;2.1.2 IPC Communication Protocol Improvement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transition from stdout-based communication to structured IPC&lt;/li&gt;
&lt;li&gt;Support multiple transport layers: Unix Socket, gRPC, WebSocket&lt;/li&gt;
&lt;li&gt;Optimize message serialization (JSON → MessagePack/CBOR)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Medium (P2)&lt;/p&gt;
&lt;h4 id="213-extensibility-and-modularization"&gt;2.1.3 Extensibility and Modularization
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider plugin architecture introduction&lt;/li&gt;
&lt;li&gt;Implement Wasm execution mode (enhanced sandboxing)&lt;/li&gt;
&lt;li&gt;Provide external agent registration API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Low (P3)&lt;/p&gt;
&lt;h4 id="214-performance-optimization"&gt;2.1.4 Performance Optimization
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zero-copy message passing&lt;/li&gt;
&lt;li&gt;Connection pooling and caching strategies&lt;/li&gt;
&lt;li&gt;Async I/O optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Medium (P2)&lt;/p&gt;
&lt;h3 id="22-discussion"&gt;2.2 Discussion
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Security Lead:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;Security channels must be applied first when improving IPC protocol. Encryption and authentication for inter-agent communication are needed.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Product Owner:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;From a user perspective, agent definitions should be more intuitive. Let&amp;rsquo;s also consider simplifying the YAML schema.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DevOps Lead:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;Performance optimization work should proceed in parallel with observability improvement. Metrics collection must be secured first to measure optimization effects.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="3-security-development-discussion"&gt;3. Security Development Discussion
&lt;/h2&gt;&lt;h3 id="31-security-lead-statement"&gt;3.1 Security Lead Statement
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;ZeroClaw already has a strong security foundation, but there are areas that need improvement from an OWASP Top 10 perspective. Sandbox isolation and audit logging enhancement are particularly urgent.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="311-sandbox-enhancement"&gt;3.1.1 Sandbox Enhancement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Current Issues:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker sandbox: &lt;code&gt;--read-only&lt;/code&gt;, &lt;code&gt;--cap-drop&lt;/code&gt;, seccomp not applied&lt;/li&gt;
&lt;li&gt;Firejail: Network isolation not applied (&lt;code&gt;--net=none&lt;/code&gt; missing)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Docker hardened profile
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker_cmd.args([
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;run&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;--rm&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--read-only&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--security-opt&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;no-new-privileges&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--cap-drop&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;ALL&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--network&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;none&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--memory&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;256m&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--pids-limit&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;64&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; High (P1)&lt;/p&gt;
&lt;h4 id="312-audit-logging-enhancement"&gt;3.1.2 Audit Logging Enhancement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce Log Signing to prevent tampering&lt;/li&gt;
&lt;li&gt;Real-time security alert webhook integration&lt;/li&gt;
&lt;li&gt;Prometheus metrics exposure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Medium (P2)&lt;/p&gt;
&lt;h4 id="313-ssrf-defense"&gt;3.1.3 SSRF Defense
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enforce HTTPS for external requests&lt;/li&gt;
&lt;li&gt;Block private IP ranges&lt;/li&gt;
&lt;li&gt;Strengthen domain allowlist validation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Medium (P2)&lt;/p&gt;
&lt;h4 id="314-toctou-vulnerability-fix"&gt;3.1.4 TOCTOU Vulnerability Fix
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Perform path validation and normalization atomically&lt;/li&gt;
&lt;li&gt;Prevent symbolic link race conditions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; High (P1)&lt;/p&gt;
&lt;h3 id="32-discussion"&gt;3.2 Discussion
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Architect:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;Sandbox enhancement can provide stronger isolation when linked with Wasm execution mode.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DevOps Lead:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;Prometheus metrics can greatly improve operational visibility when integrated with Grafana dashboards.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Product Owner:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;Ensure that security enhancements don&amp;rsquo;t degrade user experience. Defaults should be secure while advanced users can configure flexibly.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="4-product-development-discussion"&gt;4. Product Development Discussion
&lt;/h2&gt;&lt;h3 id="41-product-owner-statement"&gt;4.1 Product Owner Statement
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;ZeroClaw&amp;rsquo;s core values are &amp;lsquo;high performance&amp;rsquo;, &amp;rsquo;extensibility&amp;rsquo;, and &amp;lsquo;security&amp;rsquo;. In the first half of 2026, we need to strengthen these while improving user experience.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="411-user-experience-improvement"&gt;4.1.1 User Experience Improvement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;CLI Improvements:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improve &lt;code&gt;zeroclaw agent list&lt;/code&gt; output (table format)&lt;/li&gt;
&lt;li&gt;Interactive agent execution mode&lt;/li&gt;
&lt;li&gt;Progress visualization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Configuration Simplification:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simplify agent definition YAML schema&lt;/li&gt;
&lt;li&gt;Provide sensible defaults&lt;/li&gt;
&lt;li&gt;Improve configuration validation and error messages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; High (P1)&lt;/p&gt;
&lt;h4 id="412-documentation-and-onboarding-enhancement"&gt;4.1.2 Documentation and Onboarding Enhancement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improve Quickstart guide&lt;/li&gt;
&lt;li&gt;Auto-generate API reference documentation&lt;/li&gt;
&lt;li&gt;Expand example scenarios&lt;/li&gt;
&lt;li&gt;Multi-language documentation (Korean, Japanese, Chinese)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Medium (P2)&lt;/p&gt;
&lt;h4 id="413-community-growth-strategy"&gt;4.1.3 Community Growth Strategy
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improve CONTRIBUTING.md&lt;/li&gt;
&lt;li&gt;Label good first issues&lt;/li&gt;
&lt;li&gt;Publish regular release notes&lt;/li&gt;
&lt;li&gt;Discord/Slack community channels&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Medium (P2)&lt;/p&gt;
&lt;h4 id="414-differentiation-points-enhancement"&gt;4.1.4 Differentiation Points Enhancement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Strengthen hardware peripheral support (STM32, RPi)&lt;/li&gt;
&lt;li&gt;Specialized domain agent templates&lt;/li&gt;
&lt;li&gt;Publish performance benchmarks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Low (P3)&lt;/p&gt;
&lt;h3 id="42-discussion"&gt;4.2 Discussion
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Architect:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;CLI improvement is important from an ergonomics perspective. Let&amp;rsquo;s also consider upgrading from structopt to clap 4.x.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security Lead:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;When writing multi-language documentation, accurate translation of security-related content is important. I recommend creating a terminology glossary first.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DevOps Lead:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;For community channels, starting with GitHub Discussions is a good approach. It can be started without separate infrastructure.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="5-devops-development-discussion"&gt;5. DevOps Development Discussion
&lt;/h2&gt;&lt;h3 id="51-devops-lead-statement"&gt;5.1 DevOps Lead Statement
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;&amp;ldquo;We need to advance CI/CD pipelines and monitoring systems for stable deployment and operation.&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="511-cicd-pipeline-advancement"&gt;5.1.1 CI/CD Pipeline Advancement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Current Status:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub Actions-based CI&lt;/li&gt;
&lt;li&gt;Automated cargo fmt, clippy, test&lt;/li&gt;
&lt;li&gt;Docker build&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integrate cargo audit (vulnerability scanning)&lt;/li&gt;
&lt;li&gt;Cross-platform build (Linux, macOS, Windows)&lt;/li&gt;
&lt;li&gt;Release automation (cargo-release)&lt;/li&gt;
&lt;li&gt;Pre-deployment smoke tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; High (P1)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Proposed CI workflow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Security audit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cargo audit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Cross-platform build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;strategy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;matrix&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;os&lt;/span&gt;: [&lt;span style="color:#ae81ff"&gt;ubuntu-latest, macos-latest, windows-latest]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{ matrix.os }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="512-monitoring-and-observability"&gt;5.1.2 Monitoring and Observability
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prometheus metrics endpoint&lt;/li&gt;
&lt;li&gt;Grafana dashboard templates&lt;/li&gt;
&lt;li&gt;Distributed tracing (OpenTelemetry)&lt;/li&gt;
&lt;li&gt;Log aggregation (ELK/Loki)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Medium (P2)&lt;/p&gt;
&lt;h4 id="513-deployment-automation-and-rollback"&gt;5.1.3 Deployment Automation and Rollback
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blue-Green deployment support&lt;/li&gt;
&lt;li&gt;Automatic rollback threshold settings&lt;/li&gt;
&lt;li&gt;Canary release options&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Medium (P2)&lt;/p&gt;
&lt;h4 id="514-development-environment-improvement"&gt;5.1.4 Development Environment Improvement
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Proposals:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;devcontainer configuration&lt;/li&gt;
&lt;li&gt;Automatic git hooks setup&lt;/li&gt;
&lt;li&gt;Development configuration profiles&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; Low (P3)&lt;/p&gt;
&lt;h3 id="52-discussion"&gt;5.2 Discussion
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Architect:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;OpenTelemetry integration is essential for multi-agent tracing. Inter-agent call chains must be visualizable.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security Lead:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;cargo audit must be included in CI. It&amp;rsquo;s also good to add dependency license checks.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Product Owner:&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;devcontainer will be very helpful for new contributor onboarding. We can raise its priority.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="6-comprehensive-roadmap-and-priorities"&gt;6. Comprehensive Roadmap and Priorities
&lt;/h2&gt;&lt;h3 id="61-2026-first-half-roadmap"&gt;6.1 2026 First Half Roadmap
&lt;/h3&gt;&lt;h4 id="q1-march-april"&gt;Q1 (March-April)
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Item&lt;/th&gt;
					&lt;th&gt;Owner&lt;/th&gt;
					&lt;th&gt;Priority&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Docker/Firejail sandbox enhancement&lt;/td&gt;
					&lt;td&gt;Security&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;TOCTOU vulnerability fix&lt;/td&gt;
					&lt;td&gt;Security&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CI/CD security scan integration&lt;/td&gt;
					&lt;td&gt;DevOps&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CLI improvement and UX enhancement&lt;/td&gt;
					&lt;td&gt;Product&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DAG-based workflow engine&lt;/td&gt;
					&lt;td&gt;Architect&lt;/td&gt;
					&lt;td&gt;P1&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="q2-may-june"&gt;Q2 (May-June)
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Item&lt;/th&gt;
					&lt;th&gt;Owner&lt;/th&gt;
					&lt;th&gt;Priority&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;IPC communication protocol improvement&lt;/td&gt;
					&lt;td&gt;Architect&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Audit logging enhancement&lt;/td&gt;
					&lt;td&gt;Security&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SSRF defense implementation&lt;/td&gt;
					&lt;td&gt;Security&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Prometheus metrics exposure&lt;/td&gt;
					&lt;td&gt;DevOps&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Documentation and onboarding improvement&lt;/td&gt;
					&lt;td&gt;Product&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Community infrastructure building&lt;/td&gt;
					&lt;td&gt;Product&lt;/td&gt;
					&lt;td&gt;P2&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="62-agreed-principles"&gt;6.2 Agreed Principles
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Security First&lt;/strong&gt;: All new features must go through security review&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gradual Deployment&lt;/strong&gt;: Large changes are rolled out in stages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rollback Capable&lt;/strong&gt;: All changes must be easily rollbackable&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation Sync&lt;/strong&gt;: Documentation updates required when features change&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Coverage&lt;/strong&gt;: Tests required for new code&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="63-risks-and-responses"&gt;6.3 Risks and Responses
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Risk&lt;/th&gt;
					&lt;th&gt;Probability&lt;/th&gt;
					&lt;th&gt;Impact&lt;/th&gt;
					&lt;th&gt;Response&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Sandbox compatibility issues&lt;/td&gt;
					&lt;td&gt;Medium&lt;/td&gt;
					&lt;td&gt;High&lt;/td&gt;
					&lt;td&gt;Implement fallback mechanism&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Performance regression&lt;/td&gt;
					&lt;td&gt;Low&lt;/td&gt;
					&lt;td&gt;Medium&lt;/td&gt;
					&lt;td&gt;Automate benchmarks&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Dependency vulnerabilities&lt;/td&gt;
					&lt;td&gt;Medium&lt;/td&gt;
					&lt;td&gt;High&lt;/td&gt;
					&lt;td&gt;Automate cargo audit&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Poor documentation&lt;/td&gt;
					&lt;td&gt;High&lt;/td&gt;
					&lt;td&gt;Medium&lt;/td&gt;
					&lt;td&gt;Require documentation PRs&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="7-conclusion-and-next-steps"&gt;7. Conclusion and Next Steps
&lt;/h2&gt;&lt;h3 id="71-meeting-conclusions"&gt;7.1 Meeting Conclusions
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Architecture&lt;/strong&gt;: Prioritize multi-agent orchestration advancement&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Immediately start sandbox enhancement and TOCTOU fix&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Product&lt;/strong&gt;: Improve user experience through CLI UX improvement&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DevOps&lt;/strong&gt;: Build CI/CD security enhancement and monitoring foundation&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="72-action-items"&gt;7.2 Action Items
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;#&lt;/th&gt;
					&lt;th&gt;Item&lt;/th&gt;
					&lt;th&gt;Owner&lt;/th&gt;
					&lt;th&gt;Due Date&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;Apply Docker sandbox security profile&lt;/td&gt;
					&lt;td&gt;Security Lead&lt;/td&gt;
					&lt;td&gt;2026-03-07&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;Fix TOCTOU path validation&lt;/td&gt;
					&lt;td&gt;Security Lead&lt;/td&gt;
					&lt;td&gt;2026-03-10&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;Integrate CI cargo audit&lt;/td&gt;
					&lt;td&gt;DevOps Lead&lt;/td&gt;
					&lt;td&gt;2026-03-05&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;Improve CLI agent list&lt;/td&gt;
					&lt;td&gt;Product Owner&lt;/td&gt;
					&lt;td&gt;2026-03-12&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;Workflow engine design document&lt;/td&gt;
					&lt;td&gt;Architect&lt;/td&gt;
					&lt;td&gt;2026-03-15&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="73-next-meeting-schedule"&gt;7.3 Next Meeting Schedule
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Date&lt;/strong&gt;: 2026-03-14 10:00&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agenda&lt;/strong&gt;: Q1 progress review and Q2 detailed planning&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="appendix-reference-documents"&gt;Appendix: Reference Documents
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docs/project/multi-agent-architecture-design.md&lt;/code&gt; - Multi-agent architecture design&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs/project/multi-agent-communication-protocols.md&lt;/code&gt; - Communication protocol design&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs/security/security-improvements.md&lt;/code&gt; - Security improvement report&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt; - Engineering protocol&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Meeting Minutes Date&lt;/strong&gt;: 2026-02-28
&lt;strong&gt;Approved By&lt;/strong&gt;: ZeroClaw Team Lead
&lt;strong&gt;Distribution&lt;/strong&gt;: ZeroClaw Development Team&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Korean Version:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/ko/post/2026-02-28-001-zeroclaw-2026-h1-roadmap-meeting/" &gt;한국어 버전&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[ZeroClaw] Multi-Agent Architecture Design</title><link>https://blog.agentthread.dev/post/2026-02-27-011-zeroclaw-multi-agent-architecture-design/</link><pubDate>Fri, 27 Feb 2026 22:58:08 +0900</pubDate><guid>https://blog.agentthread.dev/post/2026-02-27-011-zeroclaw-multi-agent-architecture-design/</guid><description>&lt;h1 id="zeroclaw-multi-agent-architecture-design"&gt;ZeroClaw Multi-Agent Architecture Design
&lt;/h1&gt;&lt;h2 id="overview"&gt;Overview
&lt;/h2&gt;&lt;p&gt;ZeroClaw&amp;rsquo;s multi-agent architecture implements an advanced collaboration system evolving from a single-agent model.&lt;/p&gt;
&lt;h3 id="current-status"&gt;Current Status
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phase 1&lt;/strong&gt;: In-Process Delegation (Complete)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phase 2&lt;/strong&gt;: File-Based Multi-Agent Architecture (In Development)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="1-design-philosophy"&gt;1. Design Philosophy
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Principle&lt;/th&gt;
					&lt;th&gt;Application&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;KISS&lt;/td&gt;
					&lt;td&gt;Simple communication protocol&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;YAGNI&lt;/td&gt;
					&lt;td&gt;Implement only essential features&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SRP&lt;/td&gt;
					&lt;td&gt;Single responsibility agents&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Secure&lt;/td&gt;
					&lt;td&gt;Least privilege principle&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="2-architecture-structure"&gt;2. Architecture Structure
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Application Layer: Research │ Code │ Test Agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Message Bus Layer: NATS/Redis Pub/Sub
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Transport Layer: gRPC │ WebSocket │ Unix Socket
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="3-agent-definition"&gt;3. Agent Definition
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;agent&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;id&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;researcher&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Research Agent&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;execution&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;mode&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;subprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;provider&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;openrouter&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;model&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;claude-sonnet-4-6&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="4-cli-commands"&gt;4. CLI Commands
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent list
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent show &amp;lt;id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent run --agent-id researcher
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="5-security"&gt;5. Security
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Mode&lt;/th&gt;
					&lt;th&gt;Isolation&lt;/th&gt;
					&lt;th&gt;Use Case&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Subprocess&lt;/td&gt;
					&lt;td&gt;Process&lt;/td&gt;
					&lt;td&gt;Trusted agents&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Docker&lt;/td&gt;
					&lt;td&gt;Container&lt;/td&gt;
					&lt;td&gt;File operations&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Wasm&lt;/td&gt;
					&lt;td&gt;Memory&lt;/td&gt;
					&lt;td&gt;High security&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Korean Version:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/ko/post/2026-02-27-011-zeroclaw-multi-agent-architecture-design/" &gt;한국어 버전&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[Multi-Agent] File-Based Architecture Design</title><link>https://blog.agentthread.dev/post/2026-02-27-001-file-based-multi-agent-architecture-design/</link><pubDate>Fri, 27 Feb 2026 09:30:57 +0900</pubDate><guid>https://blog.agentthread.dev/post/2026-02-27-001-file-based-multi-agent-architecture-design/</guid><description>&lt;h1 id="file-based-multi-agent-architecture-design"&gt;File-Based Multi-Agent Architecture Design
&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;Status:&lt;/strong&gt; Design Proposal&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; multi-agent-architect&lt;br&gt;
&lt;strong&gt;Date:&lt;/strong&gt; 2026-02-24&lt;br&gt;
&lt;strong&gt;Type:&lt;/strong&gt; Alternative Architecture (Process-Per-Agent)&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="executive-summary"&gt;Executive Summary
&lt;/h2&gt;&lt;p&gt;This document defines a &lt;strong&gt;file-based, process-per-agent&lt;/strong&gt; architecture where each agent is defined as a separate configuration file and runs as an independent process. Agents are invoked on-demand and report results back to a main coordinator agent.&lt;/p&gt;
&lt;h3 id="core-principles"&gt;Core Principles
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;File-Based Agent Definition&lt;/strong&gt;: Each agent is a &lt;code&gt;.toml&lt;/code&gt; file in &lt;code&gt;agents/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Process Isolation&lt;/strong&gt;: Each agent runs in its own process&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On-Demand Invocation&lt;/strong&gt;: Main agent spawns subprocess agents as needed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reporting Protocol&lt;/strong&gt;: Structured result reporting via IPC&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero-Config Discovery&lt;/strong&gt;: Auto-discovery of agent definitions&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="1-agent-definition-file-structure"&gt;1. Agent Definition File Structure
&lt;/h2&gt;&lt;h3 id="11-directory-layout"&gt;1.1 Directory Layout
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/.zeroclaw/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── config.toml # Main configuration
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── agents/ # Agent definitions directory
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── researcher.toml # Research agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── coder.toml # Code generation agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── tester.toml # Testing agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── reviewer.toml # Code review agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── summarizer.toml # Summarization agent
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── agents.d/ # Optional: additional agent dirs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── custom/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── my_agent.toml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── workspace/ # Shared workspace
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="12-agent-file-schema"&gt;1.2 Agent File Schema
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# agents/researcher.toml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Agent metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;agent&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;researcher&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;Research Agent&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;description&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;Conducts research on given topics using web search and knowledge bases&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Execution configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;agent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;execution&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# How to run this agent: &amp;#34;subprocess&amp;#34; | &amp;#34;wasm&amp;#34; | &amp;#34;docker&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mode&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;subprocess&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Command to spawn (template variables: {agent_id}, {workspace}, {config_dir})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;command&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;zeroclaw&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt; = [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;agent&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;run&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--agent-id&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;{agent_id}&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--config&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;{config}/agents/researcher.toml&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--workspace&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;{workspace}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Working directory for the subprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;working_dir&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;{workspace}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Environment variables for the subprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;agent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;execution&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;env&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ZEROCLAW_AGENT_MODE&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;worker&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;ZEROCLAW_AGENT_ID&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;researcher&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Provider configuration (overrides main config)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;provider&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;openrouter&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;model&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;anthropic/claude-sonnet-4-6&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;api_key&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;null&lt;/span&gt; &lt;span style="color:#75715e"&gt;# Inherit from main, or set agent-specific key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;temperature&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;0.3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;max_tokens&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;4096&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Tools available to this agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[[&lt;span style="color:#a6e22e"&gt;tools&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;web_search&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[[&lt;span style="color:#a6e22e"&gt;tools&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;web_fetch&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Tools explicitly denied to this agent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[[&lt;span style="color:#a6e22e"&gt;tools&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;deny&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;reason&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;Research agent should not execute shell commands&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# System prompt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;system&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;prompt&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;You are a Research Agent. Your role is to:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;1. Search for and gather information from credible sources
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;2. Synthesize findings into structured reports
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;3. Cite sources and provide references
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;4. Avoid speculation - stick to verified information
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Memory configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;memory&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;backend&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;shared&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;shared&amp;#34; | &amp;#34;isolated&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;category&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;research&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Reporting configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;reporting&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;mode&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;ipc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;format&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;json&amp;#34;&lt;/span&gt; &lt;span style="color:#75715e"&gt;# &amp;#34;json&amp;#34; | &amp;#34;markdown&amp;#34; | &amp;#34;both&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;timeout_seconds&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Retry configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;retry&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;max_attempts&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;backoff_ms&lt;/span&gt; = &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="2-agent-registry"&gt;2. Agent Registry
&lt;/h2&gt;&lt;p&gt;The AgentRegistry discovers and manages agent definitions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentRegistry&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agents_dir: &lt;span style="color:#a6e22e"&gt;PathBuf&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agents: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, AgentDefinition&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; security: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;SecurityPolicy&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;impl&lt;/span&gt; AgentRegistry {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;new&lt;/span&gt;(agents_dir: &lt;span style="color:#a6e22e"&gt;PathBuf&lt;/span&gt;, security: &lt;span style="color:#a6e22e"&gt;Arc&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;SecurityPolicy&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Self&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;discover&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;mut&lt;/span&gt; self) -&amp;gt; Result&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;()&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self, id: &lt;span style="color:#66d9ef"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;str&lt;/span&gt;) -&amp;gt; Option&lt;span style="color:#f92672"&gt;&amp;lt;&amp;amp;&lt;/span&gt;AgentDefinition&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;list&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;self) -&amp;gt; Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="3-inter-process-communication-ipc"&gt;3. Inter-Process Communication (IPC)
&lt;/h2&gt;&lt;h3 id="task-message-main--agent"&gt;Task Message (Main → Agent)
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentTask&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; task_id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; from_agent: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; to_agent: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; prompt: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; context: &lt;span style="color:#a6e22e"&gt;HashMap&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String, serde_json::Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; input: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; timestamp: &lt;span style="color:#a6e22e"&gt;chrono&lt;/span&gt;::DateTime&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;chrono::Utc&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; deadline: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;chrono::DateTime&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;chrono::Utc&lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="result-message-agent--main"&gt;Result Message (Agent → Main)
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AgentResult&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; task_id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; agent_id: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; status: &lt;span style="color:#a6e22e"&gt;AgentStatus&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; data: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;serde_json::Value&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; output: String,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; error: Option&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;String&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; metrics: &lt;span style="color:#a6e22e"&gt;AgentMetrics&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; artifacts: Vec&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Artifact&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pub&lt;/span&gt; timestamp: &lt;span style="color:#a6e22e"&gt;chrono&lt;/span&gt;::DateTime&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;chrono::Utc&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="4-security-considerations"&gt;4. Security Considerations
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Execution Mode&lt;/th&gt;
					&lt;th&gt;Isolation&lt;/th&gt;
					&lt;th&gt;Use Case&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Subprocess&lt;/td&gt;
					&lt;td&gt;Process-level&lt;/td&gt;
					&lt;td&gt;Trusted agents&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Docker&lt;/td&gt;
					&lt;td&gt;Container&lt;/td&gt;
					&lt;td&gt;Untrusted, file operations&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Wasm&lt;/td&gt;
					&lt;td&gt;Memory-only&lt;/td&gt;
					&lt;td&gt;High security needs&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="5-cli-commands"&gt;5. CLI Commands
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# List available agents&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent list
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Show agent details&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent show &amp;lt;agent_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run an agent directly (for testing)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent run --agent-id researcher --prompt &lt;span style="color:#e6db74"&gt;&amp;#34;Research X&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Create a new agent from template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent create --id my-agent --name &lt;span style="color:#e6db74"&gt;&amp;#34;My Agent&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Validate agent definition&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;zeroclaw agent validate &amp;lt;agent_id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="6-success-criteria"&gt;6. Success Criteria
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Agent definition files validated on load&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Subprocess agents spawn and complete tasks&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; IPC protocol supports tasks &amp;gt;1GB data&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Main agent can invoke worker agents via tool&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Failed agents don&amp;rsquo;t crash main agent&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; Security policy enforced per-agent&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; CLI commands for agent management&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Korean Version:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/ko/post/2026-02-27-001-file-based-multi-agent-architecture-design/" &gt;한국어 버전&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[ZeroClaw] Codebase Architecture Analysis</title><link>https://blog.agentthread.dev/post/2026-02-26-001-zeroclaw-codebase-architecture-analysis/</link><pubDate>Thu, 26 Feb 2026 10:07:29 +0900</pubDate><guid>https://blog.agentthread.dev/post/2026-02-26-001-zeroclaw-codebase-architecture-analysis/</guid><description>&lt;h1 id="zeroclaw-codebase-architecture-analysis-report"&gt;ZeroClaw Codebase Architecture Analysis Report
&lt;/h1&gt;&lt;p&gt;&lt;em&gt;Written on February 26, 2026&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview
&lt;/h2&gt;&lt;p&gt;ZeroClaw is a high-performance autonomous agent runtime written in Rust. This report summarizes the analysis of the codebase structure and security architecture.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-core-architecture-patterns"&gt;1. Core Architecture Patterns
&lt;/h2&gt;&lt;p&gt;ZeroClaw adopts &lt;strong&gt;trait-driven extensibility&lt;/strong&gt; as its core design principle.&lt;/p&gt;
&lt;h3 id="11-major-traits-7"&gt;1.1 Major Traits (7)
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Trait&lt;/th&gt;
					&lt;th&gt;Location&lt;/th&gt;
					&lt;th&gt;Role&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Provider&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/providers/traits.rs&lt;/td&gt;
					&lt;td&gt;AI model provider interface&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Channel&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/channels/traits.rs&lt;/td&gt;
					&lt;td&gt;Communication channel interface&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Tool&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/tools/traits.rs&lt;/td&gt;
					&lt;td&gt;Tool execution interface&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Memory&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/memory/traits.rs&lt;/td&gt;
					&lt;td&gt;Memory backend interface&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Observer&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/observability/traits.rs&lt;/td&gt;
					&lt;td&gt;Observability interface&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;RuntimeAdapter&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/runtime/traits.rs&lt;/td&gt;
					&lt;td&gt;Runtime adapter interface&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Peripheral&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;src/peripherals/traits.rs&lt;/td&gt;
					&lt;td&gt;Hardware peripheral interface&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="2-security-architecture"&gt;2. Security Architecture
&lt;/h2&gt;&lt;p&gt;ZeroClaw implements security through a &lt;strong&gt;Defense-in-Depth&lt;/strong&gt; strategy.&lt;/p&gt;
&lt;h3 id="21-security-layers-6"&gt;2.1 Security Layers (6)
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SecurityPolicy Core&lt;/strong&gt; - Autonomy level management&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gateway Security&lt;/strong&gt; - Bearer token authentication&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool Validation&lt;/strong&gt; - Injection prevention&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runtime Sandbox&lt;/strong&gt; - Landlock/Firejail/Docker&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secret Management&lt;/strong&gt; - ChaCha20-Poly1305&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit Logging&lt;/strong&gt; - Event tracking&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="22-core-security-boundaries"&gt;2.2 Core Security Boundaries
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Command allowlist: 15 items&lt;/li&gt;
&lt;li&gt;Rate limiting: 20 requests/hour&lt;/li&gt;
&lt;li&gt;Environment variables: only 8 allowed&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="3-multi-agent-system"&gt;3. Multi-Agent System
&lt;/h2&gt;&lt;h3 id="implementation-roadmap"&gt;Implementation Roadmap
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Phase&lt;/th&gt;
					&lt;th&gt;Duration&lt;/th&gt;
					&lt;th&gt;Content&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1 week&lt;/td&gt;
					&lt;td&gt;Core traits, DelegateTool extension&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;2-3 weeks&lt;/td&gt;
					&lt;td&gt;Docker/Wasm execution modes&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;4+ weeks&lt;/td&gt;
					&lt;td&gt;Distributed message bus, consensus algorithm&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;ZeroClaw has an excellent architecture in terms of extensibility, security, performance, and maintainability.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;This report was written based on collaborative analysis by the ZeroClaw development team.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Korean Version:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/ko/post/2026-02-26-001-zeroclaw-codebase-architecture-analysis/" &gt;한국어 버전&lt;/a&gt;&lt;/p&gt;</description></item><item><title>[Multi-Agent] Communication Platform Design</title><link>https://blog.agentthread.dev/post/2026-02-21-003-multi-agent-platform/</link><pubDate>Sat, 21 Feb 2026 21:00:00 +0900</pubDate><guid>https://blog.agentthread.dev/post/2026-02-21-003-multi-agent-platform/</guid><description>&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;As AI agent systems evolve, the transition from single-agent to multi-agent systems is accelerating. This article explores how to design a platform architecture for efficient communication between multiple agents.&lt;/p&gt;
&lt;h2 id="1-architecture-overview"&gt;1. Architecture Overview
&lt;/h2&gt;&lt;p&gt;A multi-agent platform consists primarily of an Orchestrator, Message Bus, and various specialized agents.&lt;/p&gt;





&lt;figure class="svg-figure"&gt;
 &lt;img
 src="https://blog.agentthread.dev/images/posts/multi-agent-architecture.svg"
 alt="Multi-Agent Architecture"
 width="100%"
 height="auto"
 loading="lazy"
 style="max-width: 100%; height: auto; display: block; margin: 1.5rem auto;"
 /&gt;
 
 &lt;figcaption style="text-align: center; font-size: 0.9em; color: #666; margin-top: 0.5rem;"&gt;
 Multi-Agent Architecture
 &lt;/figcaption&gt;
 
&lt;/figure&gt;

&lt;h3 id="core-components"&gt;Core Components
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th&gt;Role&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Orchestrator&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Task coordination, agent scheduling&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Message Bus&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Inter-agent communication relay&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;State Store&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Shared state management&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Task Queue&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Priority-based work queue&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Agents&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Specialized task execution&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="2-communication-protocol-design"&gt;2. Communication Protocol Design
&lt;/h2&gt;&lt;p&gt;Inter-agent communication is designed based on asynchronous message passing.&lt;/p&gt;





&lt;figure class="svg-figure"&gt;
 &lt;img
 src="https://blog.agentthread.dev/images/posts/message-protocol.svg"
 alt="Message Protocol"
 width="100%"
 height="auto"
 loading="lazy"
 style="max-width: 100%; height: auto; display: block; margin: 1.5rem auto;"
 /&gt;
 
 &lt;figcaption style="text-align: center; font-size: 0.9em; color: #666; margin-top: 0.5rem;"&gt;
 Message Protocol
 &lt;/figcaption&gt;
 
&lt;/figure&gt;

&lt;h3 id="communication-flow"&gt;Communication Flow
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Publish&lt;/strong&gt;: Agent publishes task request to message bus&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Route&lt;/strong&gt;: Bus routes message to appropriate agent&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accept&lt;/strong&gt;: Target agent accepts task&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acknowledge&lt;/strong&gt;: Bus sends acceptance confirmation to requester&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Execute&lt;/strong&gt;: Agent performs actual work&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Result&lt;/strong&gt;: Result is published to bus&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deliver&lt;/strong&gt;: Bus delivers result to requester&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="3-message-structure"&gt;3. Message Structure
&lt;/h2&gt;&lt;p&gt;Design scalable and type-safe message structures.&lt;/p&gt;





&lt;figure class="svg-figure"&gt;
 &lt;img
 src="https://blog.agentthread.dev/images/posts/message-structure.svg"
 alt="Message Structure"
 width="100%"
 height="auto"
 loading="lazy"
 style="max-width: 100%; height: auto; display: block; margin: 1.5rem auto;"
 /&gt;
 
 &lt;figcaption style="text-align: center; font-size: 0.9em; color: #666; margin-top: 0.5rem;"&gt;
 Message Structure
 &lt;/figcaption&gt;
 
&lt;/figure&gt;

&lt;h3 id="message-envelope"&gt;Message Envelope
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;header&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;message_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;uuid-v4&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2026-02-21T12:00:00Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;source_agent&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;agent-research-01&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;target_agent&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;agent-writer-01&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;message_type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;TASK_REQUEST&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;metadata&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;priority&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;normal&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;ttl&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;3600&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;correlation_id&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;parent-uuid&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;payload&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;content_type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;json&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;encoding&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;task&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;summarize&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="message-types"&gt;Message Types
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Type&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;TASK_REQUEST&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Task request&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;TASK_RESULT&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Task result&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;STATUS_UPDATE&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Status change notification&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;HEARTBEAT&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Liveness check&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;QUERY&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Information lookup&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;RESPONSE&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Query response&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="4-agent-state-management"&gt;4. Agent State Management
&lt;/h2&gt;&lt;p&gt;Each agent has a clear state machine.&lt;/p&gt;





&lt;figure class="svg-figure"&gt;
 &lt;img
 src="https://blog.agentthread.dev/images/posts/state-management.svg"
 alt="State Management"
 width="100%"
 height="auto"
 loading="lazy"
 style="max-width: 100%; height: auto; display: block; margin: 1.5rem auto;"
 /&gt;
 
 &lt;figcaption style="text-align: center; font-size: 0.9em; color: #666; margin-top: 0.5rem;"&gt;
 State Management
 &lt;/figcaption&gt;
 
&lt;/figure&gt;

&lt;h3 id="state-transitions"&gt;State Transitions
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;IDLE → RECEIVING → PROCESSING → EXECUTING → COMPLETED → IDLE
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ↘ ↘ ↘
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ERROR ──────→ retry ──→ IDLE
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="state-behaviors"&gt;State Behaviors
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;State&lt;/th&gt;
					&lt;th&gt;Behavior&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;IDLE&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Waiting for new task&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RECEIVING&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Message reception and validation&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;PROCESSING&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Task analysis and preparation&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;EXECUTING&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Actual work execution&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;COMPLETED&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Result transmission and cleanup&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ERROR&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Error handling and retry&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="5-communication-patterns"&gt;5. Communication Patterns
&lt;/h2&gt;&lt;h3 id="51-request-response"&gt;5.1 Request-Response
&lt;/h3&gt;&lt;p&gt;Synchronous 1:1 communication pattern.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;response &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; bus&lt;span style="color:#f92672"&gt;.&lt;/span&gt;request(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; target&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;agent-code-01&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message&lt;span style="color:#f92672"&gt;=&lt;/span&gt;TaskRequest(task&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;generate_code&amp;#34;&lt;/span&gt;, spec&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#f92672"&gt;...&lt;/span&gt;}),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; timeout&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; TaskResult(status&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;, data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;generated_code)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="52-publish-subscribe"&gt;5.2 Publish-Subscribe
&lt;/h3&gt;&lt;p&gt;Asynchronous 1:N communication pattern.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Subscribe&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@bus.subscribe&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;research.completed&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handle_research_result&lt;/span&gt;(message):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Handle research result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Publish&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; bus&lt;span style="color:#f92672"&gt;.&lt;/span&gt;publish(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; topic&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;research.completed&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ResearchResult(data&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#f92672"&gt;...&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="53-broadcast"&gt;5.3 Broadcast
&lt;/h3&gt;&lt;p&gt;Used to send notifications to all agents.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Broadcast&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; bus&lt;span style="color:#f92672"&gt;.&lt;/span&gt;broadcast(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message&lt;span style="color:#f92672"&gt;=&lt;/span&gt;SystemAlert(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; level&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;warning&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;High load detected&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="6-core-design-principles"&gt;6. Core Design Principles
&lt;/h2&gt;&lt;h3 id="61-loose-coupling"&gt;6.1 Loose Coupling
&lt;/h3&gt;&lt;p&gt;Agents should not know each other&amp;rsquo;s internal implementations. They communicate only through message interfaces.&lt;/p&gt;
&lt;h3 id="62-fault-tolerance"&gt;6.2 Fault Tolerance
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Agent&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;execute_with_retry&lt;/span&gt;(self, task, max_retries&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; attempt &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(max_retries):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;execute(task)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exception&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; attempt &lt;span style="color:#f92672"&gt;==&lt;/span&gt; max_retries &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;transition_to(State&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ERROR)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;raise&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; asyncio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sleep(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt; attempt) &lt;span style="color:#75715e"&gt;# Exponential backoff&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="63-scalability"&gt;6.3 Scalability
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Horizontal scaling: Add agents with the same role&lt;/li&gt;
&lt;li&gt;Load balancing: Automatic distribution by message bus&lt;/li&gt;
&lt;li&gt;Sharding: Separate agent groups by task type&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="64-observability"&gt;6.4 Observability
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Metrics collection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@metrics.track&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;process_message&lt;/span&gt;(self, message):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; metrics&lt;span style="color:#f92672"&gt;.&lt;/span&gt;timer(&lt;span style="color:#e6db74"&gt;&amp;#34;process_duration&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;handle(message)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; metrics&lt;span style="color:#f92672"&gt;.&lt;/span&gt;increment(&lt;span style="color:#e6db74"&gt;&amp;#34;messages_processed&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; result
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="7-implementation-considerations"&gt;7. Implementation Considerations
&lt;/h2&gt;&lt;h3 id="71-message-serialization"&gt;7.1 Message Serialization
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Format&lt;/th&gt;
					&lt;th&gt;Pros&lt;/th&gt;
					&lt;th&gt;Cons&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;JSON&lt;/td&gt;
					&lt;td&gt;Readability, compatibility&lt;/td&gt;
					&lt;td&gt;Size, performance&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Protocol Buffers&lt;/td&gt;
					&lt;td&gt;Performance, schema&lt;/td&gt;
					&lt;td&gt;Complexity&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MessagePack&lt;/td&gt;
					&lt;td&gt;JSON compatible, size&lt;/td&gt;
					&lt;td&gt;Tool support&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="72-backpressure"&gt;7.2 Backpressure
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Agent&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;__init__&lt;/span&gt;(self, max_concurrent&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;semaphore &lt;span style="color:#f92672"&gt;=&lt;/span&gt; asyncio&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Semaphore(max_concurrent)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;process&lt;/span&gt;(self, message):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;async&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;semaphore:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;handle(message)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="73-dead-letter-queue"&gt;7.3 Dead Letter Queue
&lt;/h3&gt;&lt;p&gt;Failed messages are moved to a separate queue for analysis and reprocessing.&lt;/p&gt;
&lt;h2 id="8-conclusion"&gt;8. Conclusion
&lt;/h2&gt;&lt;p&gt;Key elements of a multi-agent communication platform include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Flexible message structure&lt;/strong&gt;: Support for various communication scenarios&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear state management&lt;/strong&gt;: Predictable agent behavior&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diverse communication patterns&lt;/strong&gt;: Request-response, publish-subscribe, broadcast&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fault-tolerant design&lt;/strong&gt;: Retry, timeout, error handling&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Based on these principles, scalable and reliable multi-agent systems can be built.&lt;/p&gt;
&lt;h2 id="references"&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://en.wikipedia.org/wiki/Actor_model" target="_blank" rel="noopener"
 &gt;Actor Model - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.enterpriseintegrationpatterns.com/" target="_blank" rel="noopener"
 &gt;Enterprise Integration Patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://dataintensive.net/" target="_blank" rel="noopener"
 &gt;Designing Data-Intensive Applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Korean Version:&lt;/strong&gt; &lt;a class="link" href="https://blog.agentthread.dev/ko/post/2026-02-21-003-multi-agent-platform/" &gt;한국어 버전&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>