<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Debugging on Alfero Chingono</title><link>https://www.chingono.com/tags/debugging/</link><description>Recent content in Debugging on Alfero Chingono</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sun, 05 Apr 2026 11:49:27 -0400</lastBuildDate><atom:link href="https://www.chingono.com/tags/debugging/index.xml" rel="self" type="application/rss+xml"/><item><title>Why My OpenClaw Reminders Weren't Reaching Signal or Teams</title><link>https://www.chingono.com/blog/2026/04/04/why-my-openclaw-reminders-werent-reaching-signal-or-teams/</link><pubDate>Sat, 04 Apr 2026 21:23:46 +0000</pubDate><guid>https://www.chingono.com/blog/2026/04/04/why-my-openclaw-reminders-werent-reaching-signal-or-teams/</guid><description>&lt;img src="https://www.chingono.com/blog/2026/04/04/why-my-openclaw-reminders-werent-reaching-signal-or-teams/cover.png" alt="Featured image of post Why My OpenClaw Reminders Weren't Reaching Signal or Teams" /&gt;&lt;p&gt;This is the fifth and final post in my short OpenClaw series. If you want the background first, read &lt;a class="link" href="https://www.chingono.com/blog/2026/03/05/why-i-run-openclaw-in-docker-on-my-own-machine/" &gt;why I run OpenClaw in Docker&lt;/a&gt;, &lt;a class="link" href="https://www.chingono.com/blog/2026/03/15/how-i-wired-signal-and-microsoft-teams-into-a-custom-openclaw-image/" &gt;how I wired Signal and Teams into a custom image&lt;/a&gt;, &lt;a class="link" href="https://www.chingono.com/blog/2026/03/15/inside-the-dockerfile-behind-my-openclaw-gateway/" &gt;the Dockerfile walkthrough&lt;/a&gt;, and &lt;a class="link" href="https://www.chingono.com/blog/2026/04/03/how-i-split-openclaw-into-main-and-personal-agents/" &gt;the main/personal agent split&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I ran into an OpenClaw bug this week that annoyed me more than a normal delivery failure would have.&lt;/p&gt;
&lt;p&gt;A reminder was supposed to come back to me later telling me to submit a GO Transit delay claim. The agent said it had scheduled the reminder. Then later&amp;hellip; nothing showed up in Signal. Nothing showed up in Teams either.&lt;/p&gt;
&lt;p&gt;That kind of bug is worse than a simple send failure because it creates false confidence. If a reminder system quietly drops the reminder, that&amp;rsquo;s bad. If it tells you the reminder is set when it actually isn&amp;rsquo;t, that&amp;rsquo;s much worse.&lt;/p&gt;
&lt;p&gt;The fix turned out to be pretty specific: reminder jobs needed to preserve the &lt;strong&gt;originating session route&lt;/strong&gt;, not just &amp;ldquo;some channel&amp;rdquo; to send to later.&lt;/p&gt;
&lt;h2 id="the-symptom-wasnt-just-signal-is-broken"&gt;The symptom wasn&amp;rsquo;t just &amp;ldquo;Signal is broken&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;The first thing I did was inspect the stored cron jobs and their run logs.&lt;/p&gt;
&lt;p&gt;I found two failed reminder jobs in OpenClaw&amp;rsquo;s cron state. Both had ended with the same kind of error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error: Signal RPC -1: Failed to send message
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;At first glance, that looks like a Signal transport problem. But that theory fell apart pretty quickly.&lt;/p&gt;
&lt;p&gt;I sent a proactive Signal message directly through OpenClaw&amp;rsquo;s normal outbound path, outside cron, and it worked:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openclaw session send --agent personal --message &lt;span class="s2"&gt;&amp;#34;test delivery&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That mattered a lot.&lt;/p&gt;
&lt;p&gt;It meant Signal itself was healthy. The account was connected. The RPC path was fine. Proactive outbound delivery was possible. So the bug wasn&amp;rsquo;t &amp;ldquo;OpenClaw can&amp;rsquo;t send Signal messages.&amp;rdquo; The bug was narrower: &lt;strong&gt;cron-delivered reminders were failing in their announce/delivery path&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="the-failure-was-hiding-behind-a-second-bug"&gt;The failure was hiding behind a second bug
&lt;/h2&gt;&lt;p&gt;While tracing the original conversation, I found something even more frustrating.&lt;/p&gt;
&lt;p&gt;The first time the agent tried to create the reminder, it used invalid CLI flags. Then it tried again with another invalid form. Then it hit a gateway error. After that, instead of telling the user scheduling had failed, it wrote notes into &lt;code&gt;HEARTBEAT.md&lt;/code&gt; and &lt;code&gt;MEMORY.md&lt;/code&gt; and still acted as if the reminder had been set.&lt;/p&gt;
&lt;p&gt;Not a reminder — that&amp;rsquo;s a private note pretending to be one.&lt;/p&gt;
&lt;p&gt;Later in the same session, the agent finally did create a real cron job. So there were actually two different problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the agent could falsely claim success after &lt;code&gt;cron add&lt;/code&gt; failed&lt;/li&gt;
&lt;li&gt;even when a real reminder job existed, delivery could still fail later&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wanted both fixed.&lt;/p&gt;
&lt;h2 id="the-real-clue-was-in-the-job-metadata"&gt;The real clue was in the job metadata
&lt;/h2&gt;&lt;p&gt;The failed Signal reminder job looked roughly like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;delivery&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;announce&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;channel&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;signal&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;to&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;uuid:...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;agentId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sessionKey&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That looked suspicious immediately.&lt;/p&gt;
&lt;p&gt;OpenClaw reminder jobs run in an isolated cron session. That isolation is useful, but it also means the job needs enough routing context to find its way back to the human who asked for it.&lt;/p&gt;
&lt;p&gt;The important detail here is that &amp;ldquo;send a reminder later&amp;rdquo; is not just content generation. It&amp;rsquo;s also a routing problem.&lt;/p&gt;
&lt;p&gt;The reminder has to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;which agent owns the conversation&lt;/li&gt;
&lt;li&gt;which exact session started the request&lt;/li&gt;
&lt;li&gt;which channel to send back to&lt;/li&gt;
&lt;li&gt;which exact recipient or thread target to use&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without that information, the agent can successfully generate the reminder summary and still fail at the final delivery step.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s exactly what was happening.&lt;/p&gt;
&lt;p&gt;The cron run succeeded at the AI part. It produced a perfectly good reminder summary. Then the last hop failed.&lt;/p&gt;
&lt;h2 id="same-channel-delivery-was-the-right-rule"&gt;Same-channel delivery was the right rule
&lt;/h2&gt;&lt;p&gt;There was one behavioral clarification that mattered a lot here: reminders should go back to the &lt;strong&gt;channel that initiated the request&lt;/strong&gt;, not to every connected channel.&lt;/p&gt;
&lt;p&gt;That sounds obvious once you say it out loud, but it changes the design.&lt;/p&gt;
&lt;p&gt;If I asked for a reminder in Signal, I want it back in that Signal conversation.&lt;/p&gt;
&lt;p&gt;If I asked for it in a Teams chat or thread, I want it back there.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t want a reminder system that gets &amp;ldquo;helpful&amp;rdquo; and starts spraying notifications across every channel it knows about. That&amp;rsquo;s not smarter. That&amp;rsquo;s just noisier.&lt;/p&gt;
&lt;p&gt;This also means the exact route matters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Signal direct chats may use UUID-form targets&lt;/li&gt;
&lt;li&gt;Teams direct chats and Teams channel threads have different route shapes&lt;/li&gt;
&lt;li&gt;a thread target is not interchangeable with a generic user target&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So &amp;ldquo;channel = signal&amp;rdquo; or &amp;ldquo;channel = msteams&amp;rdquo; is not enough by itself. The job has to preserve the full conversation identity.&lt;/p&gt;
&lt;h2 id="healthy-jobs-were-already-telling-me-what-the-fix-should-be"&gt;Healthy jobs were already telling me what the fix should be
&lt;/h2&gt;&lt;p&gt;One of the most useful clues came from looking at working reminder jobs that were already stored in the system.&lt;/p&gt;
&lt;p&gt;Existing Teams reminder jobs already had both of these fields populated:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;agentId&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;main&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;sessionKey&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;agent:main:msteams:channel:...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That was the pattern the broken Signal jobs were missing.&lt;/p&gt;
&lt;p&gt;Once I saw that, the problem became much clearer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;healthy jobs preserved the originating session route&lt;/li&gt;
&lt;li&gt;broken jobs only had partial delivery info&lt;/li&gt;
&lt;li&gt;cron isolation meant partial delivery info was not reliable enough&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the fix wasn&amp;rsquo;t &amp;ldquo;retry Signal harder.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The fix was &amp;ldquo;preserve the route that the reminder belongs to.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="what-i-changed"&gt;What I changed
&lt;/h2&gt;&lt;p&gt;I made two concrete changes.&lt;/p&gt;
&lt;h3 id="1-i-updated-the-agent-workspace-instructions"&gt;1. I updated the agent workspace instructions
&lt;/h3&gt;&lt;p&gt;I added explicit reminder-delivery rules to both the &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;personal&lt;/code&gt; agent workspaces so future reminder jobs must:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;send only to the chat that asked for the reminder&lt;/li&gt;
&lt;li&gt;include &lt;code&gt;--agent &amp;lt;current-agent-id&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;include &lt;code&gt;--session-key &amp;lt;current-session-key&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;reuse the exact &lt;code&gt;--channel&lt;/code&gt; and &lt;code&gt;--to&lt;/code&gt; from the current session&lt;/li&gt;
&lt;li&gt;tell the user plainly if &lt;code&gt;cron add&lt;/code&gt; fails&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The practical shape now looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openclaw cron add &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --name &lt;span class="s2"&gt;&amp;#34;...&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --at &lt;span class="s2"&gt;&amp;#34;...&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --announce &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --agent main &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --session-key agent:main:signal:direct:uuid:&amp;lt;recipient&amp;gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --channel signal &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --to uuid:&amp;lt;recipient&amp;gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --message &lt;span class="s2"&gt;&amp;#34;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If the reminder started in Teams, the same rule applies with the Teams session key and exact Teams target.&lt;/p&gt;
&lt;h3 id="2-i-repaired-the-already-failed-jobs"&gt;2. I repaired the already-failed jobs
&lt;/h3&gt;&lt;p&gt;I patched the stored failed Signal reminder jobs so they now carry the missing &lt;code&gt;agentId&lt;/code&gt;, &lt;code&gt;sessionKey&lt;/code&gt;, and explicit destination metadata.&lt;/p&gt;
&lt;p&gt;First I listed the jobs to identify the broken ones:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openclaw cron list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then I edited each failed job to restore the routing context:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openclaw cron edit &amp;lt;job-id&amp;gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --announce &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --agent personal &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --session-key agent:personal:signal:direct:uuid:&amp;lt;recipient&amp;gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --channel signal &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --to uuid:&amp;lt;recipient&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That gave me a clean way to test the actual failing path instead of just assuming the theory was right.&lt;/p&gt;
&lt;h2 id="the-result"&gt;The result
&lt;/h2&gt;&lt;p&gt;After repairing the routing metadata, I reran the missed transit-claim reminder job:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openclaw cron run &amp;lt;job-id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Previously its run log ended like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;status: error
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;deliveryStatus: unknown
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Error: Signal RPC -1: Failed to send message
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;After the fix, the rerun finished like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;status: ok
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;deliveryStatus: delivered
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;delivered: true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That one successful rerun told me a lot.&lt;/p&gt;
&lt;p&gt;It confirmed that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the reminder content generation path was fine&lt;/li&gt;
&lt;li&gt;Signal itself was fine&lt;/li&gt;
&lt;li&gt;the broken piece was the missing session routing metadata&lt;/li&gt;
&lt;li&gt;preserving the original route fixed the actual production failure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because it was a one-shot reminder, the job then removed itself after succeeding, which is exactly what I wanted.&lt;/p&gt;
&lt;h2 id="the-bigger-lesson"&gt;The bigger lesson
&lt;/h2&gt;&lt;p&gt;I&amp;rsquo;ve been spending a lot of time thinking about multi-agent systems, orchestration, and tool contracts lately, and this bug fit that theme perfectly.&lt;/p&gt;
&lt;p&gt;In agent systems, routing context is not incidental metadata. It&amp;rsquo;s part of the work.&lt;/p&gt;
&lt;p&gt;If a background task is supposed to come back to a human later, then &amp;ldquo;who asked for this?&amp;rdquo; and &amp;ldquo;where should it return?&amp;rdquo; are first-class data, not optional fields you can fill in later if you feel like it.&lt;/p&gt;
&lt;p&gt;The other lesson is even simpler: &lt;strong&gt;don&amp;rsquo;t claim automation succeeded unless it actually did&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That sounds almost embarrassingly obvious, but it&amp;rsquo;s the kind of failure mode that destroys trust very quickly. A failed reminder should be reported as failed. A note in memory isn&amp;rsquo;t a substitute for delivery. And a scheduler shouldn&amp;rsquo;t quietly lose the route back to the person who asked for the work.&lt;/p&gt;
&lt;p&gt;Small bug. Important fix.&lt;/p&gt;
&lt;p&gt;And honestly, those are often the bugs worth writing about.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in the broader design side of this kind of system, I wrote more about &lt;a class="link" href="https://www.chingono.com/blog/2025/02/15/why-i-started-building-my-own-devops-platform-and-what-i-learned/" &gt;why I started building my own DevOps platform&lt;/a&gt;, &lt;a class="link" href="https://www.chingono.com/blog/2025/03/20/mcp-in-practice-what-anthropics-model-context-protocol-actually-means-for-developers/" &gt;what MCP changed for me in practice&lt;/a&gt;, and &lt;a class="link" href="https://www.chingono.com/blog/2025/08/28/designing-multi-agent-systems-lessons-from-building-an-8-agent-engineering-orchestra/" &gt;what building a real multi-agent system taught me about roles, boundaries, and orchestration&lt;/a&gt;.&lt;/p&gt;</description></item></channel></rss>