<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rodrigo Giuliani</title>
    <description>The latest articles on DEV Community by Rodrigo Giuliani (@giulianiregspec).</description>
    <link>https://dev.to/giulianiregspec</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3914393%2Fe4bf6de5-cb4d-4bad-9a5b-d169a7634487.jpg</url>
      <title>DEV Community: Rodrigo Giuliani</title>
      <link>https://dev.to/giulianiregspec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/giulianiregspec"/>
    <language>en</language>
    <item>
      <title>You learned your hands by using them. An agent gets a paragraph.</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Thu, 03 Sep 2026 11:49:39 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/you-learned-your-hands-by-using-them-an-agent-gets-a-paragraph-4p86</link>
      <guid>https://dev.to/giulianiregspec/you-learned-your-hands-by-using-them-an-agent-gets-a-paragraph-4p86</guid>
      <description>&lt;p&gt;&lt;em&gt;A mind discovers its body by moving it, failing, and trying again. An AI agent&lt;br&gt;
controlling physical devices can do neither half of that — which is why the&lt;br&gt;
device has to introduce itself, and why nobody quite agrees on what that&lt;br&gt;
introduction should contain.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;You did not learn what your hand does by reading a specification. You spent&lt;br&gt;
about a year dropping things.&lt;/p&gt;

&lt;p&gt;Somewhere in that year you worked out that the hand grips, that grip has degrees,&lt;br&gt;
and that a glass held too loosely falls while one held too tightly breaks. Nobody&lt;br&gt;
told you. It arrived through use, through failure, and through a sense that&lt;br&gt;
reports for free, all the time, on where your limbs are and what they touch.&lt;/p&gt;

&lt;p&gt;An AI agent connected to a building full of devices has none of that.&lt;/p&gt;

&lt;p&gt;It cannot feel that a camera is there. There is no perceptual channel by which a&lt;br&gt;
language model discovers a temperature sensor in the next room the way you&lt;br&gt;
discover your own foot. And more importantly, it cannot afford the other half&lt;br&gt;
either. &lt;strong&gt;A mind learns a lock by trying the lock.&lt;/strong&gt; An agent that tries a lock&lt;br&gt;
has unlocked a door — that is not an experiment, that is an event, and it may be&lt;br&gt;
the wrong one at three in the morning.&lt;/p&gt;

&lt;p&gt;So the discovery route is closed at both ends. Which leaves exactly one option:&lt;br&gt;
the device has to say what it is.&lt;/p&gt;

&lt;p&gt;That is what a manifest is. Not a convenience, not a config format. &lt;strong&gt;It is a&lt;br&gt;
substitute for a developmental process that cannot happen.&lt;/strong&gt; And once you frame&lt;br&gt;
it that way, the interesting question stops being &lt;em&gt;what format&lt;/em&gt; and becomes&lt;br&gt;
&lt;em&gt;what does the introduction have to contain&lt;/em&gt; for a mind that will never get to&lt;br&gt;
find out by hand.&lt;/p&gt;




&lt;h2&gt;
  
  
  What most systems declare
&lt;/h2&gt;

&lt;p&gt;Almost every attempt at this — and there are several serious ones now — answers&lt;br&gt;
the same layer: &lt;strong&gt;what the thing can do.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A lock exposes &lt;code&gt;lock&lt;/code&gt; and &lt;code&gt;unlock&lt;/code&gt;. A light exposes &lt;code&gt;turn_on&lt;/code&gt; and a brightness&lt;br&gt;
parameter with a range. A thermostat exposes a target temperature in degrees. It&lt;br&gt;
is the layer that maps most cleanly onto function signatures, which is probably&lt;br&gt;
why it is the one everyone builds first.&lt;/p&gt;

&lt;p&gt;It is also genuinely necessary, and it is more than a name. A hand that "grips"&lt;br&gt;
is useless information; a hand that grips with a force between zero and forty&lt;br&gt;
newtons is something a mind can plan with. Types, ranges, units. That layer is&lt;br&gt;
mostly solved, and where it isn't, it's an implementation gap rather than a&lt;br&gt;
conceptual one.&lt;/p&gt;

&lt;p&gt;But it is not enough, and you can see why with a thought experiment that has&lt;br&gt;
nothing to do with software.&lt;/p&gt;

&lt;h2&gt;
  
  
  The layer nobody writes down
&lt;/h2&gt;

&lt;p&gt;Suppose I hand you a tool you have never seen. I tell you it has a lever, that&lt;br&gt;
the lever has two positions, and that moving it takes about two newtons.&lt;/p&gt;

&lt;p&gt;You now know exactly what it can do. You still have no idea whether to touch it.&lt;/p&gt;

&lt;p&gt;What you are missing is not capability. It is &lt;strong&gt;consequence&lt;/strong&gt;: is this reversible?&lt;br&gt;
If I move the lever and I was wrong, can I move it back? Or have I just done&lt;br&gt;
something that stays done?&lt;/p&gt;

&lt;p&gt;Your hands know this about the world and the knowledge is not in the joints. You&lt;br&gt;
handle a glass differently from a rock, and the difference is not grip strength —&lt;br&gt;
it is that one of them is unrecoverable. You learned that by breaking a glass.&lt;/p&gt;

&lt;p&gt;A device declaring &lt;code&gt;lock&lt;/code&gt; and a device declaring &lt;code&gt;turn_on&lt;/code&gt; look identical at the&lt;br&gt;
capability layer. One of them, done wrong at the wrong hour, leaves someone&lt;br&gt;
outside their own house. The other is a light you turn off again. &lt;strong&gt;Nothing in&lt;br&gt;
the interface distinguishes them&lt;/strong&gt;, and an agent reasoning only from capabilities&lt;br&gt;
has no way to be more careful with the first than the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  And the layer that isn't about the device at all
&lt;/h2&gt;

&lt;p&gt;There is a third thing, and it is the one I find hardest to place.&lt;/p&gt;

&lt;p&gt;Knowing what a hand does, and knowing that a broken glass stays broken, still&lt;br&gt;
does not tell you &lt;strong&gt;when reaching for something is the right move&lt;/strong&gt;. That&lt;br&gt;
judgement is not a property of the hand. It comes from the situation.&lt;/p&gt;

&lt;p&gt;The same is true of devices, and it produces a problem that manifests handle&lt;br&gt;
badly. A manufacturer can truthfully declare that their product opens and closes.&lt;br&gt;
They cannot declare that it is the door of an operating theatre, or that it&lt;br&gt;
matters during an evacuation, or that this particular one should never be touched&lt;br&gt;
automatically because of what is behind it. That is not information about the&lt;br&gt;
product. It is information about the deployment, and it is known only by whoever&lt;br&gt;
installed it.&lt;/p&gt;

&lt;p&gt;When those two get written into the same field — and they usually do, because&lt;br&gt;
it's convenient — something predictable happens. Ask an installer "could this&lt;br&gt;
device matter in an emergency?" and the honest answer for a light is yes. For a&lt;br&gt;
temperature sensor, also yes. For nearly everything, yes. &lt;strong&gt;The question invites a&lt;br&gt;
universal affirmative&lt;/strong&gt;, and a field where almost everything is marked relevant&lt;br&gt;
tells the agent nothing at all.&lt;/p&gt;

&lt;p&gt;The question the system actually needs is a different one: not &lt;em&gt;could this&lt;br&gt;
participate&lt;/em&gt;, but &lt;em&gt;should it&lt;/em&gt;. Those look similar and they behave nothing alike.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where the analogy breaks, and why that's the point
&lt;/h2&gt;

&lt;p&gt;Bodies do not have this problem, and it is worth being precise about why.&lt;/p&gt;

&lt;p&gt;Your hand never declared anything to you. You have no manifest. What you have is&lt;br&gt;
a decade of continuous feedback and permission to be wrong about small things&lt;br&gt;
until you stopped being wrong about them. The analogy holds right up until that&lt;br&gt;
observation and then falls apart completely — &lt;strong&gt;a mind and its body co-develop,&lt;br&gt;
and an agent and a device do not.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I don't think that weakens the comparison. I think it locates the actual&lt;br&gt;
engineering problem. Everything a manifest has to carry is there precisely&lt;br&gt;
because the loop that would otherwise teach it is unavailable, for reasons that&lt;br&gt;
are not going away. The perception gap is technical and might narrow. The&lt;br&gt;
prohibition on experimenting with locks and industrial machinery is not&lt;br&gt;
technical, and it should not narrow.&lt;/p&gt;




&lt;h2&gt;
  
  
  The open question
&lt;/h2&gt;

&lt;p&gt;I don't have a clean answer, and I am suspicious of anyone who presents one,&lt;br&gt;
because these three things are declared by three different parties who never meet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The manufacturer&lt;/strong&gt; knows what it does and what it costs to be wrong&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The installer&lt;/strong&gt; knows where it is and what it must never touch&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The situation&lt;/strong&gt; decides which of them matters right now&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most designs I've looked at, including my own, collapse at least two of those&lt;br&gt;
into one field and then wonder why the result is either too permissive or too&lt;br&gt;
brittle.&lt;/p&gt;

&lt;p&gt;So the question I'd put to anyone building in this space: &lt;strong&gt;what is the minimum a&lt;br&gt;
device must declare so that an agent can act on it correctly without ever having&lt;br&gt;
been allowed to experiment on it?&lt;/strong&gt; Not the maximum — the maximum is easy and&lt;br&gt;
nobody fills it in. The minimum.&lt;/p&gt;

&lt;p&gt;I've been trying to make this concrete in&lt;br&gt;
&lt;a href="https://dosync.dev/" rel="noopener noreferrer"&gt;DoSync&lt;/a&gt; (an open protocol I maintain). The practical&lt;br&gt;
version of the question there is more specific and more annoying: I have a field&lt;br&gt;
doing all three jobs at once, and measuring it made clear that it does none of&lt;br&gt;
them well. Which is roughly where the conceptual problem stops being conceptual.&lt;/p&gt;

&lt;p&gt;If you've built something in this space and landed somewhere different, I'd&lt;br&gt;
genuinely like to know where.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Web:&lt;/strong&gt; &lt;a href="https://dosync.dev/" rel="noopener noreferrer"&gt;https://dosync.dev/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;License:&lt;/strong&gt; Apache 2.0&lt;/p&gt;




&lt;p&gt;&lt;em&gt;DoSync — the semantic layer between AI agents and physical systems.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>agents</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Four reviewers told me the one thing I couldn't fix by myself</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Sun, 30 Aug 2026 01:51:03 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/four-reviewers-told-me-the-one-thing-i-couldnt-fix-by-myself-4p08</link>
      <guid>https://dev.to/giulianiregspec/four-reviewers-told-me-the-one-thing-i-couldnt-fix-by-myself-4p08</guid>
      <description>&lt;p&gt;&lt;em&gt;What happens when you submit a solo open-source project to academic peer review:&lt;br&gt;
the reviews were good, the paper was rejected, and the gap they found was the one&lt;br&gt;
I had no way to close on my own.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I've been building &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;DoSync&lt;/a&gt;,&lt;br&gt;
an open-source protocol that sits between AI agents and physical devices — I&lt;br&gt;
wrote about&lt;br&gt;
&lt;a href="https://dev.to/giulianiregspec/why-your-smart-home-ai-cant-open-the-door-in-an-emergency-and-how-to-fix-it-5d5i"&gt;why it exists here&lt;/a&gt;&lt;br&gt;
if you want the background.&lt;/p&gt;

&lt;p&gt;I tested it the only way I could: on my own hardware, against my own&lt;br&gt;
expectations. Then I sent it to IEEE WF-IoT 2026, because I wanted it examined by&lt;br&gt;
people who weren't me.&lt;/p&gt;

&lt;p&gt;Five reviews came back. Four were substantive. It was rejected.&lt;/p&gt;

&lt;p&gt;And here's the part that took me longest to understand: &lt;strong&gt;the reviews were&lt;br&gt;
good.&lt;/strong&gt; Two scored relevance 5 out of 5. One recommended minor revisions. The&lt;br&gt;
words included "well-written", "highly pragmatic", "a clear and defensible&lt;br&gt;
architectural stance", and — the one I keep re-reading — "unusually candid about&lt;br&gt;
limitations."&lt;/p&gt;

&lt;p&gt;Rejected anyway. Not because the idea was wrong. Because of this, from the most&lt;br&gt;
detailed review:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The evaluation is small and self-judged: 15 scenarios with ground truth&lt;br&gt;
defined by the author alone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sentence is correct, and no amount of rewriting section 4 was going to&lt;br&gt;
change it.&lt;/p&gt;




&lt;h2&gt;
  
  
  I got exactly what I asked for
&lt;/h2&gt;

&lt;p&gt;It took me a few days to notice that the rejection was the thing I'd submitted&lt;br&gt;
for.&lt;/p&gt;

&lt;p&gt;I didn't send the paper hoping for a stamp. I sent it because after months of&lt;br&gt;
being the only person who had ever evaluated this, I had no way to tell the&lt;br&gt;
difference between "this works" and "this works the way I expect it to." Four&lt;br&gt;
strangers read it carefully and told me. That is not a consolation prize — it is&lt;br&gt;
the entire reason to submit.&lt;/p&gt;

&lt;p&gt;What they said, in summary: the architecture holds up, and the evidence doesn't&lt;br&gt;
reach as far as the claims. One reviewer went further and put the knife somewhere&lt;br&gt;
specific. My central claim is that the project removes the manual burden of&lt;br&gt;
writing device-by-device automation rules. Their objection:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;if resolution quality depends on well-curated tags, the manual configuration&lt;br&gt;
burden has not been eliminated, it has moved from rules to manifest curation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've had months to find a counter-argument. I don't have one yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  The one thing I couldn't fix by myself
&lt;/h2&gt;

&lt;p&gt;The request that came up in almost every review was for independent annotators.&lt;br&gt;
Not more scenarios — different people. Someone other than me who had read a&lt;br&gt;
scenario, looked at the devices available, and formed their own opinion about&lt;br&gt;
which ones should respond.&lt;/p&gt;

&lt;p&gt;I couldn't produce one. Every judgement about what the resolver &lt;em&gt;should&lt;/em&gt; pick —&lt;br&gt;
in all fifteen scenarios, in the paper and in the benchmark files — was mine.&lt;br&gt;
When I disagreed with the resolver, I was the one who had decided what the right&lt;br&gt;
answer was in the first place.&lt;/p&gt;

&lt;p&gt;Everything else on the reviewers' list, I could work on alone, and did. The&lt;br&gt;
evaluation used to run on a single home registry, which is a poor way to support&lt;br&gt;
a claim of being domain-agnostic; there's now a&lt;br&gt;
&lt;a href="https://github.com/giulianireg-spec/dosync-protocol/tree/main/benchmarks/corpus" rel="noopener noreferrer"&gt;multi-domain corpus&lt;/a&gt;&lt;br&gt;
covering industrial and clinical registries, published so the numbers are&lt;br&gt;
reproducible by someone who isn't me. The precision/recall conventions that made&lt;br&gt;
two rows of a results table mathematically impossible are defined and the bug is&lt;br&gt;
traced. There's a sensitivity analysis on the scoring weights.&lt;/p&gt;

&lt;p&gt;None of that required anyone else. The annotators do. That asymmetry turned out&lt;br&gt;
to be the most useful thing in the whole review packet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Distribution is harder than building, and worth more
&lt;/h2&gt;

&lt;p&gt;Since the reviews, I've been doing the closest thing to third-party testing that&lt;br&gt;
one person can do: installing my own project on machines that had never run it,&lt;br&gt;
following my own published instructions, on hardware that owed me nothing.&lt;/p&gt;

&lt;p&gt;It found more than a dozen defects in a week, on a codebase with about a thousand&lt;br&gt;
passing tests. My favourite: device discovery had been silently dead in&lt;br&gt;
production for days, because a dependency I'd added shipped an event loop that&lt;br&gt;
&lt;em&gt;declares&lt;/em&gt; a method and raises when you call it. My check was &lt;code&gt;hasattr&lt;/code&gt;. It&lt;br&gt;
returned &lt;code&gt;True&lt;/code&gt;. Every test passed and nothing was ever discovered.&lt;/p&gt;

&lt;p&gt;Not one of those was findable from the inside. My test suite ran on one operating&lt;br&gt;
system, one event loop, one machine that already had everything configured — it&lt;br&gt;
was measuring a world only I lived in. Which is, word for word, what the reviewer&lt;br&gt;
said about my evaluation.&lt;/p&gt;

&lt;p&gt;That's the part I'd pass on to anyone building something alone: &lt;strong&gt;the hardest&lt;br&gt;
work isn't the next feature. It's getting the thing into the hands of someone who&lt;br&gt;
doesn't already know how it's supposed to behave&lt;/strong&gt; — including your own hands, on&lt;br&gt;
a machine that has never seen it.&lt;/p&gt;

&lt;p&gt;The protocol is open, the corpus is public, and the one thing it still needs is&lt;br&gt;
an opinion that isn't mine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Web:&lt;/strong&gt; &lt;a href="https://dosync.dev/" rel="noopener noreferrer"&gt;https://dosync.dev/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;License:&lt;/strong&gt; Apache 2.0&lt;/p&gt;




&lt;p&gt;&lt;em&gt;DoSync — the semantic layer between AI agents and physical systems.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The reviews are summarised faithfully and the reviewers stay anonymous, as they&lt;br&gt;
should.)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>architecture</category>
      <category>iot</category>
    </item>
    <item>
      <title>MCP Already Connects Your AI to Everything. So What Would DoSync Add?</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Sat, 18 Jul 2026 20:17:52 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/mcp-already-connects-your-ai-to-everything-so-what-would-dosync-add-49ef</link>
      <guid>https://dev.to/giulianiregspec/mcp-already-connects-your-ai-to-everything-so-what-would-dosync-add-49ef</guid>
      <description>&lt;p&gt;If you've connected an AI assistant to anything this year, your calendar, your files, a database, GitHub, there's a good chance MCP was doing the connecting. The Model Context Protocol has quietly become the standard way an AI reaches beyond its chat window: one&lt;br&gt;
protocol, thousands of tools, plug and play. It's genuinely good, and it's everywhere.&lt;/p&gt;

&lt;p&gt;So when a project like DoSync shows up describing itself as a protocol between AI and physical devices, the fair question is: why would I need that? My AI already calls tools through MCP. Isn't controlling a lamp just another tool call?&lt;/p&gt;

&lt;p&gt;That's the right question, people keep searching for the difference between MCP and DoSync as if they were rivals, and I want to answer it honestly, including the part where the answer is "you probably don't need DoSync." Full disclosure before anything&lt;br&gt;
else: &lt;strong&gt;I build DoSync.&lt;/strong&gt; Read everything below with that in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP is, precisely
&lt;/h2&gt;

&lt;p&gt;MCP is an open protocol, introduced by Anthropic, that standardizes how an AI application connects to tools and data. Before it, every integration was bespoke: one connector for your calendar, another for your database, each written against each AI product. MCP replaces that with a single contract, an AI client on one side, any number of "MCP servers" on the other, each server exposing tools the model can discover and call.&lt;/p&gt;

&lt;p&gt;The metaphor everyone uses is USB-C, and it's earned: one port, anything plugs in. To say it precisely rather than metaphorically: MCP defines how a model &lt;em&gt;discovers&lt;/em&gt; what tools exist and &lt;em&gt;invokes&lt;/em&gt; them, it moves the request and the result, faithfully, in both&lt;br&gt;
directions. What the tool actually does when called is entirely the tool's business.&lt;br&gt;
&lt;strong&gt;Transport isn't judgment&lt;/strong&gt;, and that's not a flaw, it's the design. Keep that phrase, the whole rest of this post hangs on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; whenever an AI needs to reach something outside itself. Which today is almost always. If your AI reads your email, queries a database, or files a ticket, MCP is the right layer, and it is complete for that job. Nothing below changes that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DoSync is, precisely
&lt;/h2&gt;

&lt;p&gt;DoSync is an open protocol (Apache 2.0) that sits between an AI and &lt;em&gt;physical devices&lt;/em&gt;, lights, locks, sensors, alarms. It does one job: it turns a goal expressed in plain terms into a coordinated, supervised, recorded set of physical actions.&lt;/p&gt;

&lt;p&gt;The word doing the work there is &lt;em&gt;goal&lt;/em&gt;. You don't send DoSync "turn on lamp 3, then lamp 4, then unlock the door." You send it an intent, &lt;em&gt;ensure_safety&lt;/em&gt; and a resolver (the part that works out which devices matter) matches it against capabilities the devices&lt;br&gt;
themselves declared when they joined. Then three things happen that no generic tool layer does for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The operator's own rules apply.&lt;/strong&gt; Policies are a space's standing rules, declared in a file its operator controls — "never unlock these doors overnight," "this zone stays out of alarm patterns," "sirens need explicit confirmation." The AI doesn't need to remember these, and can't talk its way around them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every action is recorded&lt;/strong&gt; in a tamper-evident audit log — what acted, when, and why, in a hash chain where altering history is detectable. Not a debug log: a record you could show someone afterward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Completion is confirmed, not assumed.&lt;/strong&gt; A command being &lt;em&gt;accepted&lt;/em&gt; is not the same as it being &lt;em&gt;done&lt;/em&gt; — DoSync waits for the device to confirm reality before calling a step finished.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use it:&lt;/strong&gt; when the "tool" your AI is calling is the physical world, and getting it wrong has consequences beyond a failed API call.&lt;/p&gt;

&lt;h2&gt;
  
  
  They're not rivals. One literally speaks the other.
&lt;/h2&gt;

&lt;p&gt;Here's the part that dissolves the versus framing: &lt;strong&gt;DoSync ships as an MCP server.&lt;/strong&gt; The way an AI reaches DoSync &lt;em&gt;is&lt;/em&gt; MCP.&lt;/p&gt;

&lt;p&gt;Picture any building full of devices, an office, a clinic, a warehouse, a store. It's 2 a.m. and something goes wrong. The person responsible types one sentence to an AI: &lt;em&gt;"there's an emergency in the building."&lt;/em&gt; Corridor lights go to full, exit doors unlock, the alarm fires, the on-call people get a message, as one coordinated response, not twenty lucky ones. Walk backward through what happened: the model understood the sentence (that's the AI), found and called a tool named &lt;code&gt;dosync_fire_intent&lt;/code&gt; (that's MCP doing exactly its job — delivering the call), and that one call became a coordinated, recorded response across every relevant device (that's DoSync). Three layers, one loop, zero conflict. (This isn't hypothetical machinery, to be clear, the reference implementation runs this exact loop 24/7 on real hardware; the scenario is generic because the protocol is: nothing in it assumes what kind of building it's serving.)&lt;/p&gt;

&lt;p&gt;Now give the building one rule of its own, because every real one has them. Say it's a care facility, and one wing houses patients who must never be startled by flashing lights — so the operator declared a policy: &lt;em&gt;that wing's lights stay out of alarm patterns. No exceptions. Not even in an emergency.&lt;/em&gt; When the emergency fires, the resolver proposes — &lt;em&gt;correctly&lt;/em&gt; — every device capable of helping, including those lights: they genuinely can flash, and they truthfully say so. The policy removes them before anything fires, and the record shows both facts: what was proposed, and what the&lt;br&gt;
building's own rules decided. Notice that nobody made a mistake, not the model, not the transport, not the resolver. Everyone did their job right, and the operator's judgment about &lt;em&gt;their own building&lt;/em&gt; still had the last word. That's the layer.&lt;/p&gt;

&lt;p&gt;At a glance:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;MCP&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;DoSync&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What is it?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A standard for connecting AI to tools and data&lt;/td&gt;
&lt;td&gt;A semantic layer between AI and physical devices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What does it solve?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Discovery and invocation — one protocol instead of bespoke integrations&lt;/td&gt;
&lt;td&gt;Coordination and judgment — goals become supervised physical action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The unit of work&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A tool call&lt;/td&gt;
&lt;td&gt;An intent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Who decides what's safe?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The tool being called&lt;/td&gt;
&lt;td&gt;The operator's declared policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Where does it run?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Wherever client and servers live — local or cloud&lt;/td&gt;
&lt;td&gt;Locally, in the building it serves — no cloud required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use it when...&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your AI needs to reach &lt;em&gt;anything&lt;/em&gt; external&lt;/td&gt;
&lt;td&gt;The thing being reached is the physical world, and mistakes have consequences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Made by&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Anthropic (open protocol)&lt;/td&gt;
&lt;td&gt;One independent dev (open, Apache 2.0)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What DoSync adds to MCP
&lt;/h2&gt;

&lt;p&gt;If you're building agents that touch the physical world, DoSync makes MCP &lt;em&gt;safer to use seriously&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One tool instead of fifty.&lt;/strong&gt; Without a coordination layer, an agent controlling a building full of devices needs a tool per device per action, and the model has to orchestrate twenty calls correctly, in order, under pressure. With DoSync, the agent calls one tool with one goal — the orchestration happens below, deterministically, where a language model's bad day can't scramble it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A place for the owner's rules to live.&lt;/strong&gt; MCP deliberately has no opinion about what a tool should refuse — that's the tool's job. DoSync is where those refusals are declared once, by the human who owns the space, and enforced regardless of what the AI asks for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A record.&lt;/strong&gt; When an agent acts on the world, "what exactly happened and why" stops being a debugging question and becomes an accountability one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What MCP adds to DoSync
&lt;/h2&gt;

&lt;p&gt;This direction matters just as much, and it's the reason DoSync didn't invent its own AI interface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Every MCP-speaking AI is already a DoSync client.&lt;/strong&gt; Claude today; any model or agent framework that speaks MCP, tomorrow, no per-model integration, no SDK to maintain. MCP gave DoSync its entire front door for free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The intelligence stays where it belongs.&lt;/strong&gt; DoSync deliberately contains no language model. Understanding "make sure everything's safe for the night" is the AI's craft; MCP is what lets that understanding arrive as a clean, structured intent. DoSync gets smarter every time the models do, without changing a line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the honest shape of it: MCP without something like DoSync can &lt;em&gt;reach&lt;/em&gt; the physical world but brings no judgment to it. DoSync without MCP would be a nervous system with no brain attached. Each one makes the other worth more.&lt;/p&gt;

&lt;h2&gt;
  
  
  And here's the part most projects won't say
&lt;/h2&gt;

&lt;p&gt;For the vast majority of what people use MCP for today — email, calendars, code, files, databases — &lt;strong&gt;you do not need DoSync.&lt;/strong&gt; MCP alone is complete for that, full stop. Even for casual device control — "turn on the porch light" — an MCP server for your smart-home platform covers it, and adding a coordination layer would be infrastructure earning you nothing.&lt;/p&gt;

&lt;p&gt;DoSync earns its place only when three things matter &lt;em&gt;at the same time&lt;/em&gt;: one goal has to fan out across many devices reliably, the operator's own rules must hold even when the AI is wrong, and you need a trustworthy record of what acted and why. A cold-chain failure in a store at 3 a.m. — the manager woken, the sector locked, maintenance dispatched, before the stock is lost, with proof afterward of exactly what fired and why. That's the narrow set of cases, and it looks the same whether the building is a store, a clinic, or a home. Outside it, stay with MCP alone and enjoy it — that's not modesty, it's me not selling you a layer you won't use.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they actually fit together
&lt;/h2&gt;

&lt;p&gt;The picture isn't MCP versus DoSync. It's a loop: &lt;strong&gt;the AI thinks, MCP connects, DoSync acts with judgment&lt;/strong&gt; — and telemetry closes the circle back to the AI. If you're building&lt;br&gt;
agents that stop at screens, you already have everything you need. If yours are starting to reach into the world, that last layer is the part I've been building — and if you're not sure which side of the line you're on, open an issue describing your case and I'll&lt;br&gt;
tell you straight.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
Web (with a 2-minute live demo): &lt;a href="https://dosync.dev/" rel="noopener noreferrer"&gt;https://dosync.dev/&lt;/a&gt;&lt;br&gt;
License: Apache 2.0&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I Gave an AI One Sentence. A Drone Flew the Mission — and When the AI Guessed Wrong, the System Caught It.</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Wed, 24 Jun 2026 05:13:48 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/i-gave-an-ai-one-sentence-a-drone-flew-the-mission-and-when-the-ai-guessed-wrong-the-system-2h3m</link>
      <guid>https://dev.to/giulianiregspec/i-gave-an-ai-one-sentence-a-drone-flew-the-mission-and-when-the-ai-guessed-wrong-the-system-2h3m</guid>
      <description>&lt;p&gt;&lt;em&gt;A build log: connecting DoSync, an open semantic-intent protocol, to a real autonomous-vehicle stack — then letting an AI model command it in plain language, and watching what happened when the model made a mistake.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I've spent the last while building &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;DoSync&lt;/a&gt;, an open protocol (Apache 2.0) that lets AI agents act on physical devices through &lt;strong&gt;semantic intent&lt;/strong&gt; instead of commands. The AI says &lt;em&gt;"there's an emergency"&lt;/em&gt;; the devices figure out their own roles, from the capabilities they declared when they joined.&lt;/p&gt;

&lt;p&gt;The protocol was designed to be domain-agnostic from the start — nothing in it assumes a house, a vehicle, or a factory. But a design claim is cheap. The only honest way to find out whether "domain-agnostic" is true is to take the protocol to the hardest possible device and see if it holds. So I connected it to a drone — and then I did the thing the protocol was always &lt;em&gt;for&lt;/em&gt; but that I'd never actually shown: I let an AI model fire the intents, from a single sentence in plain language.&lt;/p&gt;

&lt;p&gt;This post is the build log of both halves — the hard plumbing, and the moment it all closed into a loop. Including the moment the AI got it wrong, which turned out to be the most important part. Because the lesson underneath all of it is a simple one: &lt;strong&gt;the AI can be wrong; the protocol does not have to be.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a drone is the hard case
&lt;/h2&gt;

&lt;p&gt;A light bulb is the easy case. You say "turn on," it turns on, done. The action is instantaneous and it never fails in a way that matters.&lt;/p&gt;

&lt;p&gt;A drone is the opposite on every axis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its actions &lt;strong&gt;take time&lt;/strong&gt;. "Go to this point" isn't done when the command is accepted — it's done minutes later, when the aircraft arrives.&lt;/li&gt;
&lt;li&gt;It passes through states. Arming, taking off, navigating, holding position in wind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silence is not success.&lt;/strong&gt; If the drone stops reporting, that doesn't mean it arrived. It might mean the radio link dropped while it kept flying.&lt;/li&gt;
&lt;li&gt;A human can take over at any instant by grabbing the RC sticks — and when they do, the system must know and back off, not fight them.&lt;/li&gt;
&lt;li&gt;Getting it wrong has physical consequences.
If an orchestration protocol can handle that, the rest is downhill.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I had to build
&lt;/h2&gt;

&lt;p&gt;Until the drone, every action DoSync knew was instantaneous — fire it, get a result, done. A vehicle breaks that assumption completely. To speak to one, I built a few new layers — and the interesting part is how few of them are actually about drones.&lt;/p&gt;

&lt;h3&gt;
  
  
  A general model for long-running operations
&lt;/h3&gt;

&lt;p&gt;First, a state machine for any action that takes time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pending → in_progress → completed | failed
        + rejected, cancelled, interrupted
        + sub-states: preparing, paused_by_device, reconciling
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crucially, &lt;strong&gt;this knows nothing about drones.&lt;/strong&gt; It's the same model an oven, a 3D printer, or a robotic arm would use. &lt;code&gt;interrupted&lt;/code&gt; means a human took control — of a drone or of anything else.&lt;/p&gt;

&lt;h3&gt;
  
  
  A command channel and a telemetry channel — over one link
&lt;/h3&gt;

&lt;p&gt;A MAVLink adapter translates DoSync's aerial intents (&lt;code&gt;take_off&lt;/code&gt;, &lt;code&gt;go_to&lt;/code&gt;, &lt;code&gt;return_home&lt;/code&gt;, &lt;code&gt;land&lt;/code&gt;, &lt;code&gt;loiter&lt;/code&gt;) into the drone's native protocol. The key design rule: when the drone accepts a command, that's &lt;strong&gt;dispatch acceptance, not completion&lt;/strong&gt;. "I received the order" ≠ "I arrived." The protocol keeps that distinction honest.&lt;/p&gt;

&lt;p&gt;The other half is a telemetry listener that reads the drone's continuous stream and only marks an operation complete on a &lt;strong&gt;positive signal&lt;/strong&gt; — the aircraft actually reaching its target altitude, actually arriving at a waypoint, actually disarming after it lands. Never on the absence of an error.&lt;/p&gt;

&lt;p&gt;Getting these two channels to share one connection turned out to be the whole game, and it's worth being honest about why. My first instinct was two connections — one to send commands, one to listen. It fails immediately: a real drone over a serial radio is a &lt;em&gt;single&lt;/em&gt; bidirectional link. A serial port can't be opened twice. Trying to fake two channels over UDP produced a cascade of subtle failures — a port bind conflict, then lost acknowledgements, then commands addressed to "system 0" because the command channel never heard the heartbeat that identifies the vehicle. Each one looked like a different bug. They were all the same bug: &lt;strong&gt;a blind command channel.&lt;/strong&gt; The fix was to stop pretending. One connection, owned by the listener (the single reader); the command writes on it and waits for its acknowledgement &lt;em&gt;through&lt;/em&gt; the listener. That's exactly how a real ground station handles a single radio link — it's the architecture a physical aircraft demands, not a shortcut that only holds up in simulation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Safety policies that filter intent
&lt;/h3&gt;

&lt;p&gt;Two policies, both &lt;em&gt;absolute&lt;/em&gt; (they don't bypass even in an emergency):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;geofence&lt;/strong&gt; that blocks any destination outside a permitted perimeter. An emergency is never a reason to fly somewhere dangerous.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;manual-control lockout&lt;/strong&gt; that blocks commands to a vehicle a human is flying. An emergency is very likely &lt;em&gt;why&lt;/em&gt; they took control — it must never wrestle it back.
These filter the &lt;em&gt;intent&lt;/em&gt; before dispatch. They are &lt;strong&gt;not&lt;/strong&gt; the flight safety system — that lives in the drone's firmware and acts on its own, even if DoSync vanishes. DoSync coordinates; it is never the failsafe. That boundary is the whole philosophy.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Testing it without risking a real aircraft
&lt;/h2&gt;

&lt;p&gt;I validated everything against &lt;strong&gt;ArduPilot SITL&lt;/strong&gt; — the same software-in-the-loop simulator the drone industry develops against. A complete virtual drone, speaking real MAVLink, that you can command and that reports real telemetry.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(A note on honesty: this is validated in SITL, not yet on physical hardware. SITL is serious validation — it's what the industry builds against — but a real aircraft flying is the next step, not a claim I'm making today.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And here's where the build log stops being about plumbing and starts being about the point.&lt;/p&gt;




&lt;h2&gt;
  
  
  The part that matters: an AI commands the drone
&lt;/h2&gt;

&lt;p&gt;For most of this build, &lt;em&gt;I&lt;/em&gt; was the one firing the intents — a &lt;code&gt;POST&lt;/code&gt; to the hub, by hand. The loop worked, but there was a quiet gap between what DoSync &lt;em&gt;is&lt;/em&gt; and what I'd actually shown. DoSync's whole premise is that &lt;strong&gt;an AI expresses a goal and the physical system figures out the rest.&lt;/strong&gt; Yet if the "AI" is a &lt;code&gt;curl&lt;/code&gt; command I type, a reader can't tell it apart from a scheduled task. The essence — &lt;em&gt;a model deciding to act&lt;/em&gt; — wasn't on screen.&lt;/p&gt;

&lt;p&gt;So I closed the gap. DoSync ships a native MCP server, which means any LLM that speaks MCP can use the hub as a tool. I pointed a model at it — a small, fast one, Claude Haiku — and, in plain Spanish, told it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Use the drone to inspect the perimeter of the area centered at latitude -35.3632, longitude 149.1652, with a 50-meter radius at 30 meters altitude."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I never named an intent. I never gave a waypoint. I described a goal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fng6pwzrq5gyt2742s7dn.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fng6pwzrq5gyt2742s7dn.webp" alt="The AI receives a plain-language instruction and fires the inspect_area intent on its own" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model did the translation itself: it recognized that "inspect the perimeter" maps to the &lt;code&gt;inspect_area&lt;/code&gt; intent, built the structured context (the center, the radius, the altitude, the target vehicle), and fired it at the hub. It even inferred the city from the coordinates and chose a priority on its own. &lt;strong&gt;That translation — from a human goal to a semantic intent — is the entire reason DoSync exists.&lt;/strong&gt; And notably, it didn't take a frontier model to do it: a small, fast model handled the mapping cleanly, because the hard part isn't raw reasoning — it's having a protocol with a vocabulary the model can target.&lt;/p&gt;

&lt;p&gt;One detail worth highlighting for anyone building on MCP: the model didn't have &lt;code&gt;inspect_area&lt;/code&gt; hardcoded anywhere. The MCP server reads the available intents from the hub at runtime — the hub is the single source of truth. I had declared &lt;code&gt;inspect_area&lt;/code&gt; on the hub earlier in the day; the model simply &lt;em&gt;saw&lt;/em&gt; it appear as an available capability. Declare a new intent on the hub, and the AI layer can use it with no code change. That's the protocol's "everything is declared" principle reaching all the way up to the model.&lt;/p&gt;




&lt;h2&gt;
  
  
  Watching the loop close
&lt;/h2&gt;

&lt;p&gt;The moment the intent fired, the hub composed the route — take off, fly the four corners of the perimeter, return home — and drove it step by step. Each step waited for confirmed arrival before the next began.&lt;/p&gt;

&lt;p&gt;Here is the hub's own log. Notice that every &lt;code&gt;go_to accepted&lt;/code&gt; (the command was received) is followed, seconds later, by a &lt;code&gt;reached go_to target — FINISHED&lt;/code&gt; (the aircraft actually got there). Command acceptance and completion are kept distinct, exactly as designed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6ob7ycku47rfezl2pygr.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6ob7ycku47rfezl2pygr.webp" alt="The hub log: each waypoint command is followed by a telemetry-confirmed arrival" width="800" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is the drone itself, in SITL — arming, taking off, climbing, flying the pattern, switching to RTL, and landing under its own firmware:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv1pl5uq0xo17j8vr9szy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv1pl5uq0xo17j8vr9szy.webp" alt="ArduPilot SITL: the drone arms, takes off, flies, returns and disarms" width="800" height="721"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DO_SET_MODE → ARM → NAV_TAKEOFF → height 25 → RTL → Hit ground → DISARMED.&lt;/code&gt; (That &lt;code&gt;Hit ground at 0.5 m/s&lt;/code&gt; is SITL's blunt way of logging a normal touchdown — a controlled landing, not a crash.) A complete autonomous mission, from a sentence spoken to an AI.&lt;/p&gt;

&lt;p&gt;The last link took the most care. A &lt;code&gt;take_off&lt;/code&gt; confirms by reaching its commanded &lt;strong&gt;altitude&lt;/strong&gt;. A &lt;code&gt;go_to&lt;/code&gt; confirms by reaching a &lt;strong&gt;position&lt;/strong&gt;. But &lt;code&gt;return_home&lt;/code&gt;? RTL ends when the aircraft lands and shuts its motors down — so it confirms by the &lt;strong&gt;disarm&lt;/strong&gt;. Three different real-world signals for "done," each one a positive fact pulled from telemetry, none of them an assumption. Silence completes nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  When the AI gets it wrong — and why that's the good part
&lt;/h2&gt;

&lt;p&gt;The first time I asked, I gave no coordinates. The model, trying to be helpful, filled the gap with &lt;em&gt;my&lt;/em&gt; location — Córdoba, Argentina — and fired the intent. The drone in SITL starts in Canberra. So the AI had just ordered an aircraft to fly to a waypoint &lt;strong&gt;11,000 km away.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's what I care about: the system did &lt;strong&gt;not&lt;/strong&gt; pretend that worked. The command was accepted, the supervisor waited for a confirmed arrival, none came, and after its timeout it aborted the mission with a clear diagnosis — &lt;code&gt;go_to stalled (no positive signal)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's the whole safety posture in one event — the lesson from the intro, now with a drone behind it. &lt;strong&gt;The AI can be wrong. The protocol does not have to be.&lt;/strong&gt; An LLM filling a missing parameter with a plausible guess is exactly the kind of failure these systems will have in the real world — and the right answer is not to trust the model harder. It's to build a substrate that confirms physical reality and refuses to fake success. DoSync coordinates; the drone's firmware flies; the telemetry tells the truth; and when the truth is "it never arrived," the mission stops.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it actually revealed
&lt;/h2&gt;

&lt;p&gt;Here's the thing I didn't fully expect. Of everything I built, &lt;strong&gt;almost none of it is drone code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The state machine is generic. The telemetry reconciler is generic. The supervisor that waits for confirmed arrival is device-agnostic — an oven finishing a bake would use it identically. The manual-control policy applies to anything a human can grab. Only the MAVLink adapter and its message parser are drone-specific — and those are exactly the pieces a &lt;em&gt;new&lt;/em&gt; device would swap out.&lt;/p&gt;

&lt;p&gt;So the same infrastructure already reaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;robotic arm&lt;/strong&gt; — reach, grip, move, release; an operator can take physical control.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;3D printer&lt;/strong&gt; — hours-long jobs with phases that can fail midway.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;EV charger&lt;/strong&gt; — "charge to 80%," interruptible, reporting state.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;ground rover&lt;/strong&gt; — the same &lt;code&gt;go_to&lt;/code&gt;, the same geofence, without the flying.
The drone didn't expand DoSync's scope. It &lt;strong&gt;proved&lt;/strong&gt; the scope the protocol was designed to have all along. It was the hardest test, not the origin.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;DoSync is an orchestration layer for cyber-physical systems — &lt;em&gt;an AI expresses what should happen, the device executes with its own safety reflexes, a human can always take over, and the telemetry never lies about what actually occurred.&lt;/em&gt; The lights and sensors it can also drive are just the easy end of that same spectrum; the drone is the hard end.&lt;/p&gt;

&lt;p&gt;The drone was simply the hardest way to prove it. And the proof isn't that a drone flew a square. It's that &lt;strong&gt;a sentence to a model became a confirmed autonomous mission&lt;/strong&gt; — and that when the model guessed wrong, the system caught it.&lt;/p&gt;

&lt;p&gt;The protocol is open. The hard case works. The next case is whatever device you have that does something that takes time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Web:&lt;/strong&gt; &lt;a href="https://dosync.dev/" rel="noopener noreferrer"&gt;https://dosync.dev/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;License:&lt;/strong&gt; Apache 2.0&lt;/p&gt;




&lt;p&gt;&lt;em&gt;DoSync — the semantic layer between AI agents and physical systems.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>robotics</category>
      <category>iot</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Home Assistant Already Talks to Your Devices. So What Would DoSync Add?</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Tue, 16 Jun 2026 03:00:49 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/home-assistant-already-talks-to-your-devices-so-what-would-dosync-add-1iei</link>
      <guid>https://dev.to/giulianiregspec/home-assistant-already-talks-to-your-devices-so-what-would-dosync-add-1iei</guid>
      <description>&lt;p&gt;If you run Home Assistant, you've already solved the hardest problem in the smart home: talking to three thousand kinds of device. Lights, locks, sensors, vacuums, obscure Zigbee gadgets from a brand that no longer exists — HA speaks to all of them. And since 2025 it ships an MCP server, so an AI assistant can already reach in and control them.&lt;br&gt;
So when a project like DoSync shows up describing itself as a protocol between AI and physical devices, the fair question from anyone in the HA community is: why would I need that? I already have HA, and now AI can talk to HA directly.&lt;br&gt;
That's the right question, and I want to answer it honestly — including the part where the answer is "you probably don't."&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Home Assistant is, precisely&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;HA does three jobs: it integrates with devices, it runs automations, and it gives you a UI. The first job is the one that matters here, and it's genuinely excellent. HA is the richest device-integration layer that exists. Nothing should try to replace that, and DoSync doesn't — it reads devices from HA through a bridge that's already in the repo.&lt;br&gt;
But notice what HA's model is, underneath: it's still commands. "Turn on light.living_room." "Set climate.bedroom to 21." The HA MCP server exposes those same commands to an AI. The intelligence about what to do — what should happen when there's an emergency, when nobody's home, when a sensor reads something strange — lives either in an automation you wrote in advance, or in the AI sending the commands. HA executes; it doesn't decide.&lt;br&gt;
That's not a criticism. It's just the layer HA operates at: it aggregates devices and gives you a uniform way to command them.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Where a different layer might sit&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;DoSync operates one layer up, and only does one thing: it turns a semantic intent into a coordinated, auditable set of actions.&lt;br&gt;
You don't tell it "turn on these ten lights, unlock that door, send this SMS." You express a goal — ensure_safety, away_mode — and a resolver decides which devices are relevant based on what they've declared they can do, executes the actions, and writes every one of them to a tamper-evident SHA-256 audit log. The devices can come from HA, or from a direct adapter (WiZ over UDP, GPIO on a Pi, BLE, MQTT). HA is one source of "bodies," not the center.&lt;br&gt;
Three things distinguish that from sending commands through the HA MCP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Intents, not commands. The AI says what it wants to achieve; the resolver works out the rest from declared device capabilities. Add a device and it participates automatically — no automation to rewrite.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An audit log built for accountability. Every action and the reason it fired, in a SHA-256 hash chain: each entry includes the hash of the previous one, so editing or deleting a past entry breaks the chain and is detectable on verification. To be precise about what that buys you — it protects against undetected after-the-fact modification of the history, not against an attacker with root on the hub (who could rewrite the whole chain). HA's recorder and logbook give you a searchable history, which is great for "what happened"; the hash chain adds "and you can show it wasn't altered" — which matters when an auditor, an insurer, or an incident review needs a record they can trust, and matters not at all for everyday automation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multiple sources under one contract. DoSync coordinates devices from HA and from other adapters under a single semantic model with policies and certification. HA is one especially rich source among several.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;And here's the part most projects won't say&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For the vast majority of what people use Home Assistant for — "turn on the porch light when I get home," "set the thermostat back at night" — you do not need DoSync. HA's own automations and its MCP server cover that completely. Adding a coordination layer would be extra infrastructure earning you nothing.&lt;br&gt;
DoSync earns its place only when two things are true at once: coordination matters (one goal has to fan out across many devices, reliably, possibly in an emergency) and traceability matters (you need an auditable record of what acted and why).&lt;br&gt;
A concrete home example: an elderly parent lives alone, and you've built a fall-response setup — a sensor trips and the home should unlock the door for paramedics, turn every light to full, and message the family, all at once, and you need to be able to say afterward exactly what fired and when. That's coordination plus traceability in a house, not a factory. Outside cases like that — most of what HA does day to day — the extra layer earns you nothing.&lt;br&gt;
If that's not your situation, stay with HA and enjoy it. That's not me being modest; it's me not wanting to sell you a layer you won't use.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How they actually fit together&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The honest picture isn't DoSync versus Home Assistant. It's DoSync using Home Assistant — treating HA as one of the best places to source devices, and adding a semantic, auditable coordination layer above it for the narrow set of cases that need one. HA keeps owning its integrations. The connecting AI stays where the intelligence belongs — outside, expressing intent. DoSync is just the nervous system in between.&lt;br&gt;
If you're in that narrow set of cases, it's worth a look. If you're not, you already have what you need — and if you're genuinely not sure which side of the line you're on, open an issue describing your setup and I'll tell you straight whether it's worth the trouble.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
Web: &lt;a href="https://dosync.dev/" rel="noopener noreferrer"&gt;https://dosync.dev/&lt;/a&gt;&lt;br&gt;
License: Apache 2.0&lt;/p&gt;

</description>
      <category>homeassistant</category>
      <category>ai</category>
      <category>opensource</category>
      <category>iot</category>
    </item>
    <item>
      <title>When Automatic Failover Is More Dangerous Than No Failover</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Sun, 14 Jun 2026 15:25:07 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/when-automatic-failover-is-more-dangerous-than-no-failover-2c9o</link>
      <guid>https://dev.to/giulianiregspec/when-automatic-failover-is-more-dangerous-than-no-failover-2c9o</guid>
      <description>&lt;p&gt;Here's a counterintuitive thing I ran into building redundancy for DoSync, an open protocol that lets AI agents act on physical devices: the obvious failover design can hurt you more than having no failover at all.&lt;br&gt;
Let me show you why.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;DoSync runs a hub — the process that turns a semantic intent ("there's an emergency") into coordinated device actions, and writes every action to an audit log. That log is a SHA-256 hash chain: each entry includes the hash of the previous one, so any edit to history breaks the chain and is detectable. It's the part of the system that lets you answer "what happened, and when?" with confidence.&lt;br&gt;
One hub is a single point of failure. So the natural move is to add a standby that takes over when the primary dies. The naive design writes itself: the standby pings the primary every few seconds, and after N missed heartbeats it promotes itself to primary.&lt;br&gt;
It works perfectly in a demo. It's dangerous in a house.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The trap: split-brain&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Picture two hubs on your LAN. The network partitions — not the primary crashing, just the link between the two going away. The primary is alive and well, still serving its devices. But the standby can't see it.&lt;br&gt;
So the standby promotes itself. Now you have two primaries, both convinced they're in charge, both writing to the audit log. The hash chain that made that log tamper-evident diverges into two incompatible histories. The one guarantee the whole system is built on — you can always reconstruct what happened — is gone.&lt;br&gt;
A missed heartbeat doesn't tell you "the primary is dead." It tells you "I can't reach the primary." Those are very different statements, and the naive design treats them as the same.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The fix is mostly about honesty&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The real solution to split-brain is a quorum — three nodes voting, à la Raft. But for a home or a small building, that's overkill, and you usually don't have a third node anyway.&lt;br&gt;
So I went with something simpler and more honest: assisted failover. Two changes.&lt;br&gt;
First, before the standby concludes anything, it runs a second probe against an independent target on the LAN (the gateway):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;primary unreachable + gateway reachable  → primary is probably down
primary unreachable + gateway also down  → *I* am probably the problem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one extra check separates two failure modes the naive design conflates. It is not a substitute for quorum — it doesn't help in every partition (if both hubs can still see the gateway but not each other, the probe tells you nothing). What it cheaply catches is the most common home case: the standby itself losing its network. When that happens, the standby enters an UNCERTAIN state and refuses to act.&lt;br&gt;
Second — even when it does think the primary is down, it doesn't promote itself. It proposes promotion to a human. A person can glance at the situation and see whether the primary is actually alive. A 5-second heartbeat timeout cannot.&lt;br&gt;
(To be clear, this whole multi-hub layer is opt-in. A single hub runs exactly as before — redundancy is for people who want it, not a requirement.)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Testing it on real hardware&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I ran this on two real machines — a Raspberry Pi (primary) and a laptop (standby) — because this is exactly the kind of behavior that only shows up with real network conditions, not in unit tests.&lt;br&gt;
Killing the primary process: standby detected it, gateway probe still succeeded, proposed promotion. Good.&lt;br&gt;
Pulling the standby's network while the primary stayed up: standby saw both targets go dark, went UNCERTAIN, and stayed quiet. In that test, the only difference between "propose promotion" and "stay quiet" was the gateway probe — one bit of extra information deciding between a safe outcome and a corrupted log.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The takeaway&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Availability features have a failure mode of their own. An automatic action taken on bad information can be worse than no action plus a clear signal to a human. For anything writing to physical state — locks, alarms, logs you can't afford to corrupt — "fail loudly and ask" is often a better default than "fail over silently," at least until you have real consensus to back automatic promotion.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DoSync&lt;/em&gt; is open source (Apache 2.0). If you want to poke holes in this design — and I'd genuinely like that — it's at &lt;a href="//dosync.dev"&gt;dosync.dev&lt;/a&gt;. The failover logic is a small, dependency-free state machine; criticism welcome.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>distributedsystems</category>
      <category>architecture</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why your smart home breaks the moment you add an AI agent</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Wed, 03 Jun 2026 01:27:33 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/why-your-smart-home-breaks-the-moment-you-add-an-ai-agent-3i4e</link>
      <guid>https://dev.to/giulianiregspec/why-your-smart-home-breaks-the-moment-you-add-an-ai-agent-3i4e</guid>
      <description>&lt;p&gt;You add a new smoke detector to your home network. It registers with the hub. Thirty seconds later, when someone fires an &lt;code&gt;ensure_safety&lt;/code&gt; intent, the detector is part of the response — no automation written, no rule updated, no developer intervention.&lt;br&gt;
How is that possible?&lt;br&gt;
The answer is capability abstraction. And it's the design decision that separates systems that work with AI from systems that merely tolerate it.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The device that knows its own role&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Every existing smart home protocol treats a device as a passive endpoint. The device waits. Something external — an app, a rule engine, a developer's script — decides when to call it and what to tell it. The device's only job is to execute.&lt;br&gt;
This model has a hidden assumption: that someone, somewhere, anticipated every scenario the device would be relevant for. They wrote the rule. They tested it. They kept it updated as new devices joined the network.&lt;br&gt;
That assumption holds when humans are in the loop. It breaks the moment an AI agent enters the picture — because the AI doesn't have the rulebook. It has a goal. And the gap between "I have a goal" and "I know which devices to activate" is exactly the integration problem that makes AI-IoT systems fragile.&lt;br&gt;
The fix is to move the knowledge of when a device is relevant from the rulebook into the device itself.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The Capability Manifest — a declaration, not an API&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In DoSync, every device publishes a Capability Manifest when it joins the network. Here's a real one from the production deployment — a Philips WiZ bulb running on a Raspberry Pi 5:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;json&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wiz-living1-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"device_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Living Room — Bulb 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manufacturer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Philips"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WiZ RGBW Tunable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"firmware"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"actuator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"light"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"climate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"smart-plug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"emergency"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wiz"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actuators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wiz-living1-01-turn_on"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"turn_on"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Turn on"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wiz-living1-01-turn_off"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"turn_off"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Turn off"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wiz-living1-01-set_brightness"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"set_brightness"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Set brightness 0-100%"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wiz-living1-01-set_color"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"set_color"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Set RGB color"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sensors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"emergency_capable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"adapter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wiz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"adapter_config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192.168.100.28"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't an API specification. It's a declaration of identity and relevance. The device is answering three questions at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What can I do? — turn on, turn off, set brightness, set color&lt;/li&gt;
&lt;li&gt;Where do I fit? — I'm a light, I'm a smart plug, I'm an &lt;code&gt;emergency&lt;/code&gt; device&lt;/li&gt;
&lt;li&gt;When do I matter? — I'm emergency-capable; include me when safety is at stake&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI agent never needs to know the device's native protocol. It fires:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;json&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"intent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ensure_safety"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"urgency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"emergency"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resolver reads every registered manifest, scores each device for relevance — weighting tag overlap, location context, emergency bonus, and actuator match — and builds the action plan. The bulb is included because of its &lt;code&gt;emergency&lt;/code&gt; tag and &lt;code&gt;emergency_capable&lt;/code&gt;: true — not because anyone hardcoded it. Add ten more bulbs tomorrow with the same manifest structure, and they participate immediately in every emergency response.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;emergency_capable&lt;/code&gt; is a contract, not a flag&lt;br&gt;
This boolean deserves more attention than it usually gets.&lt;br&gt;
When a device declares emergency_capable: true, it's not filling in a form field. It's making a commitment to the protocol:&lt;br&gt;
&lt;em&gt;I will respond to emergency intents without confirmation. I accept being included in the audit trail as a critical actor. I understand that my actions in emergencies will be logged with a tamper-evident SHA-256 chain.&lt;/em&gt;&lt;br&gt;
The protocol enforces this contract. Emergency-capable devices bypass the normal policy evaluation flow. They're always included as candidates in emergency intent resolution, regardless of tag overlap. And every action they take is logged — precisely because actions taken during emergencies are consequential enough to require a verifiable record.&lt;br&gt;
This is the correct place for a safety guarantee to live. Not in a rule written by a developer who may or may not have anticipated the edge case. In the device's own declaration, verified and enforced by the protocol at runtime.&lt;br&gt;
Compare the two designs:&lt;br&gt;
Rule-based:  developer writes "if emergency, unlock frontdoor-01"&lt;br&gt;
             → breaks when frontdoor-01 is replaced&lt;br&gt;
             → breaks when a second entrance is added&lt;br&gt;
             → breaks when the emergency scenario changes&lt;/p&gt;

&lt;p&gt;Capability:  device declares emergency_capable: true&lt;br&gt;
             → protocol enforces the contract&lt;br&gt;
             → survives device replacement, new entrances, new scenarios&lt;br&gt;
             → audit trail is automatic&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why this is different from OpenAPI, MCP, and service registries&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Capability abstraction is an old pattern. OpenAPI schemas describe what an HTTP service can do. MCP tool descriptions tell an LLM which tools are available and when to use them. Service registries in microservices architectures let services announce themselves at runtime.&lt;br&gt;
DoSync's Capability Manifest is in this family. But there's a specific difference that matters for physical systems.&lt;br&gt;
OpenAPI and MCP describe interfaces — the exact shape of inputs and outputs. They're precise but context-free. An OpenAPI schema for a door lock tells you the &lt;code&gt;/unlock&lt;/code&gt; endpoint accepts a &lt;code&gt;duration_seconds&lt;/code&gt; integer. It doesn't tell you that this lock is at the main entrance, that it's relevant in emergencies, or that it should be included in a safety response but not an energy-saving routine.&lt;br&gt;
The Capability Manifest adds semantic context on top of interface description. The &lt;code&gt;tags&lt;/code&gt; field isn't a type system — it's a declaration of relevance across scenarios. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;["door-lock", "entrance", "emergency"]&lt;/code&gt;&lt;br&gt;
 tells the resolver three things that no API schema can express: what the device is, where it lives, and when it matters.&lt;br&gt;
This distinction exists because AI agents reason at the semantic level, not the API level. An LLM detecting an emergency thinks "there's a safety situation" — not "send a PUT request to /api/v1/lock/frontdoor-01/state with body &lt;code&gt;{locked: false, duration: 300}"&lt;/code&gt;. The abstraction layer has to meet the AI where it operates — at the level of meaning, not syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The device as a participant&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here's the shift capability abstraction enables, stated plainly:&lt;br&gt;
In the command model, adding a device means updating your automations. The device is inert until a human decides it should participate in something.&lt;br&gt;
In the capability model, adding a device is the integration. The manifest is the contract. From the moment it registers, the device participates in every scenario it declared itself relevant for.&lt;br&gt;
Before:  new device → engineer writes automation → device participates in scenario A&lt;br&gt;
         new scenario B → engineer writes automation → device participates in scenario B&lt;/p&gt;

&lt;p&gt;After:   new device registers manifest → device participates in all relevant scenarios&lt;br&gt;
         new scenario added to protocol → device participates automatically&lt;br&gt;
This is not a small operational difference. In a home with 40+ devices, maintaining the "before" model means hundreds of automation rules, each one a potential failure point when a device changes or a scenario is updated. The "after" model has one integration surface per device — the manifest — and it never needs to be updated when scenarios change.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What the manifest teaches manufacturers&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you're building a device that will coexist with AI agents, the Capability Manifest is the interface that matters more than your API documentation.&lt;br&gt;
A well-designed manifest answers the questions AI systems actually ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Will this device respond in an emergency? → &lt;code&gt;emergency_capable&lt;/code&gt;: &lt;code&gt;true/false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;What kind of device is this? → &lt;code&gt;category&lt;/code&gt; + semantic &lt;code&gt;tags&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;What can it physically do? → &lt;code&gt;actuators&lt;/code&gt; with meaningful type names&lt;/li&gt;
&lt;li&gt;What can it sense? → &lt;code&gt;sensors&lt;/code&gt; with type and unit&lt;/li&gt;
&lt;li&gt;How does the protocol talk to it? → &lt;code&gt;adapter&lt;/code&gt; + &lt;code&gt;adapter_config&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A poorly designed manifest — missing location tags, wrong &lt;code&gt;emergency_capable&lt;/code&gt; value, generic actuator types — means the device is invisible to the AI in exactly the scenarios where it should matter most. The resolver can only work with what the device declares.&lt;br&gt;
Tag your devices correctly. The rest is automatic.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The idea worth keeping&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Five posts ago, we started with a simple observation: AI agents express goals, not commands. Every post since then has been an answer to the same question — what does a system have to look like, at each layer, to bridge that gap?&lt;br&gt;
Semantic intent replaced commands. Policies replaced rules. Events were separated from intents. And now capability abstraction replaces the developer who used to be the translator between device APIs and AI goals.&lt;br&gt;
The translator was always the fragile part. Every time a device changed, the translator broke. Every time a new scenario appeared, the translator had to be updated. Every time an AI agent expressed something that wasn't anticipated, the translator failed silently.&lt;br&gt;
Capability abstraction removes the translator. The device speaks for itself. The AI listens. The protocol enforces the contracts between them.&lt;br&gt;
That's not a smart home feature. That's the infrastructure for any physical environment where AI needs to act reliably.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;GitHub: &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
Website: &lt;a href="https://dosync.dev" rel="noopener noreferrer"&gt;https://dosync.dev&lt;/a&gt;&lt;br&gt;
License: Apache 2.0&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>iot</category>
      <category>architecture</category>
      <category>dosync</category>
    </item>
    <item>
      <title>Rules Aren't Enough Once an AI Is in the Loop</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Sat, 30 May 2026 03:06:15 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/rules-arent-enough-once-an-ai-is-in-the-loop-5cdg</link>
      <guid>https://dev.to/giulianiregspec/rules-arent-enough-once-an-ai-is-in-the-loop-5cdg</guid>
      <description>&lt;p&gt;Picture this: it's 03:00. A camera detects that an elderly person has fallen in the bedroom. The AI agent fires &lt;code&gt;ensure_safety [emergency]&lt;/code&gt;. The action plan includes unlocking the front door so emergency services can get in.&lt;br&gt;
But someone wrote a rule three months ago: never unlock after midnight.&lt;br&gt;
The rule wins. The door stays locked. The paramedics arrive and can't get in.&lt;br&gt;
This is not a bug in the AI. It's not a bug in the rule — in any other context, locking the door at night is exactly right. It's a design problem — and it's the exact problem that appears when you build physical AI systems on top of automation logic that was never designed for an AI to act on.&lt;br&gt;
The difference between a rule and a policy looks small from a distance. Both constrain behavior. Both say "don't do X in situation Y." But they operate at different levels of the system — and getting this distinction wrong in a physical environment has real consequences.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What a rule is&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A rule is a static, pre-written instruction that maps a condition to an action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;motion_detected&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;away_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;alarm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;turn_on&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rules live in the automation layer. They're written by a human, at configuration time, for a specific scenario that was anticipated in advance. They're deterministic in the right circumstances: given the same input, they always produce the same output.&lt;br&gt;
Rules work well when the world is predictable, the device set is stable, and a human is always the one deciding what to do. They've been the foundation of home automation for fifteen years for exactly this reason. Nothing in this article argues that rules are wrong or should be replaced — they're the right tool for scheduling, thresholds, and simple automations that a human configured deliberately. A rule that turns on the porch light at sunset doesn't need a policy — it has no safety implications, no edge cases, and no AI acting on it. Rules fail not because they're a bad idea, but because they were never designed to compose with an autonomous agent that can fire arbitrary intents at arbitrary times.&lt;br&gt;
But rules have a structural weakness: they can only respond to situations that were anticipated when they were written. And when an AI agent starts firing intents, the space of possible situations grows faster than anyone can write rules for.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What breaks when AI enters the picture&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;An AI agent doesn't write rules. It fires intents.&lt;br&gt;
When a vision model detects someone who has fallen, it doesn't execute alarm.activate() and phone.call("911") — it fires ensure_safety [emergency]. When a model infers that nobody is home, it doesn't iterate through a list of devices and turn them off one by one — it fires save_energy [info].&lt;br&gt;
The intent expresses a goal. The protocol figures out how to achieve it.&lt;br&gt;
But here's the problem: once you have an AI agent firing intents, you need a way to constrain what it can and can't do — without writing a rule for every possible scenario. You need something that can evaluate intent against context at runtime, not something that was pre-written for a specific situation.&lt;br&gt;
You need a policy engine.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The difference that matters&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A rule answers: &lt;em&gt;what should happen when X occurs?&lt;/em&gt;&lt;br&gt;
A policy answers: &lt;em&gt;is this action permitted, given who's asking, what they want to do, and when?&lt;/em&gt;&lt;br&gt;
The distinction is not cosmetic. It changes the entire structure of how you think about safety in a physical system.&lt;br&gt;
Consider a front door lock. With rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Rule 1: lock at midnight
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Rule 2: unlock for delivery window
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;delivery_expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These rules handle the scenarios they were written for. But what happens when an AI agent fires &lt;code&gt;control_access [emergency]&lt;/code&gt; at 03:00 because it detected an intruder? What happens when a different AI agent fires &lt;code&gt;away_mode&lt;/code&gt; which includes an unlock action? What happens when two intents fire simultaneously and both want to act on the lock?&lt;br&gt;
Rules don't compose. Each rule was written in isolation, without knowledge of the others. In a system where an AI can fire arbitrary intents at arbitrary times, the rule surface grows unbounded — and the gaps between rules are exactly where accidents happen.&lt;br&gt;
A policy is different:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;pythonNeverAfterHoursPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;actuator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unlock&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lock-frontdoor-01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;blocked_hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;      &lt;span class="c1"&gt;# never unlock 00:00–06:00
&lt;/span&gt;    &lt;span class="n"&gt;except_urgency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;emergency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# unless it's an emergency
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This policy applies to every intent that would unlock the front door, regardless of which AI fired it, regardless of what scenario triggered it. It's declared once. It evaluates at runtime. It composes with other policies automatically.&lt;br&gt;
And it has an explicit emergency exception — because in a physical system, the rule "never unlock after midnight" has to be breakable in genuine emergencies. Rules can't express that nuance cleanly. Policies can.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What a policy engine actually does&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In DoSync, every intent passes through the PolicyEngine before execution. The engine evaluates the action plan against all configured policies and returns one of four verdicts:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ALLOW&lt;/code&gt; — proceed as planned&lt;br&gt;
&lt;code&gt;BLOCK&lt;/code&gt; — reject the intent entirely&lt;br&gt;
&lt;code&gt;CONFIRM&lt;/code&gt; — hold execution and request human confirmation&lt;br&gt;
&lt;code&gt;MODIFY&lt;/code&gt; — allow execution but remove or adjust specific actions&lt;/p&gt;

&lt;p&gt;This happens between the resolver (which decides what to do) and the executor (which actually does it). The AI never bypasses this layer — not even for emergency intents, which bypass policy constraints at the urgency level, not by circumventing the engine entirely.&lt;br&gt;
In DoSync, this looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="c1"&gt;# An AI fires save_energy at 02:00
&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntentClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SAVE_ENERGY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;urgency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Urgency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trigger&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;occupancy_inferred_empty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# The resolver builds an action plan:
# → turn_off: wiz-living-01..10
# → turn_off: wiz-hallway-01       ← this one is excluded by policy
# → set_temperature: thermostat-01
&lt;/span&gt;
&lt;span class="c1"&gt;# The PolicyEngine evaluates:
# DeviceExclusionPolicy: hallway light excluded from save_energy → MODIFY
# ContextualWeightingPolicy: 02:00 on a weekday → weight reduced but ALLOW
&lt;/span&gt;
&lt;span class="c1"&gt;# The executor receives the modified plan:
# → turn_off: wiz-living-01..10
# → set_temperature: thermostat-01
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI expressed a goal. The protocol decided how to achieve it. The policy engine ensured the result was safe — without the AI needing to know anything about the hallway light policy, or the time-based weighting, or which devices are excluded from which intents.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why this matters beyond the home&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The rule/policy distinction becomes critical at scale and in regulated environments.&lt;br&gt;
In a hotel, a rule that says "turn off lights when nobody is in the room" works until a guest leaves their laptop charging and the system decides the room is empty. A policy that says "never cut power to outlet circuits in occupied rooms regardless of occupancy inference" handles the edge case — without needing a rule for every possible device state.&lt;br&gt;
In a hospital, a rule that says "lock all doors at 22:00" breaks the moment a crash cart needs to move between floors. A policy that says "door locks revert to unlocked state on emergency_capable override, regardless of schedule" is robust to the scenario that matters most — the one nobody wanted to think about at configuration time.&lt;br&gt;
In a factory, a rule that says "shut down line B if temperature exceeds threshold" doesn't compose with the rule that says "never shut down line B during a shift change handover." A ConflictResolutionPolicy that assigns priorities to intents and resolves contention explicitly is the right abstraction — not an ever-growing set of conditional rules that interact in unpredictable ways.&lt;br&gt;
The pattern is always the same: rules break at the boundaries between anticipated scenarios. Policies compose across all of them.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;The audit implication&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There's one more difference that matters in regulated environments: auditability.&lt;br&gt;
A rule that fires an action leaves a trace, but the reasoning is implicit — buried in the automation logic that evaluated the condition. If something goes wrong, you can see what happened, but reconstructing why requires reading the rule code.&lt;br&gt;
A policy verdict is explicit. Every intent execution in DoSync's audit log records what happened, what the resolver decided, and what the executor did — in a tamper-evident SHA-256 chained record. The reasoning is in the system's configuration (which policies are active, with what parameters), not buried in conditional logic that has to be reverse-engineered after the fact.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;json&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"intent_executed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"intent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"save_energy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"urgency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"failed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a3f7..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prev_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9c12..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters for post-incident analysis. It matters for regulatory compliance. And it matters for the fundamental accountability question in any AI-augmented physical system: when something goes wrong, can you reconstruct exactly what the system decided and why?&lt;br&gt;
With rules, the answer is usually "mostly." With policies, the answer is "yes, completely."&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The deeper point&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Rules encode what to do. Policies encode what's permitted.&lt;br&gt;
When a human is always in the loop, rules are enough — the human's judgment fills the gap between what the rules say and what should actually happen. When an AI agent is in the loop, that judgment gap has to be filled by the infrastructure.&lt;br&gt;
That's what a policy engine is for. Not to constrain the AI arbitrarily, but to make the system's safety model explicit, configurable, and auditable — so that the AI can act autonomously within a boundary that a human defined deliberately.&lt;br&gt;
The AI expresses goals. The protocol executes them. The policy engine ensures the result is safe.&lt;br&gt;
That's the contract a physical AI system needs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DoSync Protocol: &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
License: Apache 2.0&lt;/em&gt;&lt;/p&gt;

</description>
      <category>iot</category>
      <category>ai</category>
      <category>architecture</category>
      <category>security</category>
    </item>
    <item>
      <title>How I Used GitHub Copilot to Turn a Half-Finished Protocol Into a Certified Standard published</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Wed, 27 May 2026 02:23:47 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/how-i-used-github-copilot-to-turn-a-half-finished-protocol-into-a-certified-standardpublished-20cd</link>
      <guid>https://dev.to/giulianiregspec/how-i-used-github-copilot-to-turn-a-half-finished-protocol-into-a-certified-standardpublished-20cd</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-05-21"&gt;GitHub Finish-Up-A-Thon Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;DoSync Protocol is an open-source communication protocol (Apache 2.0) that lets AI agents control physical devices using semantic intentions instead of commands. Instead of lock.unlock(), an AI agent says ensure_safety — and every registered device figures out its own role automatically.&lt;br&gt;
The Python reference implementation was running in production on a Raspberry Pi 5. But a protocol with only one implementation isn't a standard — it's a library. The unfinished piece: a second independent Node.js implementation that could pass the DoSync certification suite.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq0t78qi7je8xbvprrfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq0t78qi7je8xbvprrfx.png" alt="VS Code with GitHub Copilot Chat suggesting the GET /v1/status endpoint on the right, and the terminal showing DoSync Standard certification passing 11/11 on the left" width="800" height="424"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;── Tier BASIC ─────────────────────────────────────────────
  ✓  Hub reachable — version 0.1.0
  ✓  Protocol version declared — dosync/0.1
  ✓  Device can register — registered
  ✓  Device appears in registry — 1 device registered
  ✓  Hub returns device detail — status=200
  ✓  Capability manifest has all required fields — all present
── Tier STANDARD — Intents and events ─────────────────────
  ✓  Hub accepts notify_family intent — 4 actions executed
  ✓  Intent resolves correctly — 4 actions processed
  ✓  Device can send event — received
  ✓  Hub rejects unknown intents with 422 — status=422
  ✓  Hub rejects unregistered device events with 404 — status=404
── Result ──────────────────────────────────────────────────
  Tests passed: 11
  Tests failed: 0
  ✓ CERTIFIED — DoSync STANDARD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Comeback Story
&lt;/h2&gt;

&lt;p&gt;Before: The Node.js implementation (implementations/dosync-node) passed Basic certification (6/6 tests) — it could register devices and handle simple queries. But Standard tier was failing at test 1 because the server was missing GET /v1/status, the endpoint the certification suite uses to verify hub identity and protocol version.&lt;br&gt;
Additionally, the certification CLI (certify.py) only supported HTTP — but the production hub runs on HTTPS with a local PKI. Running Standard tests against real infrastructure was impossible.&lt;br&gt;
What changed:&lt;br&gt;
certify.py — fixed to support real deployments:&lt;/p&gt;

&lt;p&gt;HTTPS support with CA certificate validation via DOSYNC_CA_CERT&lt;br&gt;
Bearer token injection via DOSYNC_TOKEN&lt;br&gt;
Localhost detection: HTTP for local dev, HTTPS for remote&lt;br&gt;
Connectivity test fixed to use /v1/status instead of / (which returns the HTML dashboard)&lt;/p&gt;

&lt;p&gt;dosync-node — the missing endpoint, added with Copilot:&lt;/p&gt;

&lt;p&gt;GET /v1/status — the single endpoint that unlocked Standard certification&lt;/p&gt;

&lt;p&gt;After: dosync-node passes DoSync Standard certification (11/11). Two independent implementations in different languages, same protocol, same certification suite — the minimum criterion for an open standard.&lt;/p&gt;
&lt;h2&gt;
  
  
  My Experience with GitHub Copilot
&lt;/h2&gt;

&lt;p&gt;Copilot contributed in two ways during this session.&lt;br&gt;
Inline suggestions while editing certify.py. As I was modifying the HTTP helper to support HTTPS and token injection, Copilot's inline suggestions consistently anticipated the next line — the SSL context setup, the os.environ.get() calls, the exception handling pattern. It didn't write the logic, but it reduced the friction of writing boilerplate correctly on the first pass.&lt;br&gt;
The endpoint that closed the gap. Once I identified that GET /v1/status was the missing piece, I asked Copilot Chat:&lt;/p&gt;

&lt;p&gt;"I'm implementing the DoSync Protocol in Node.js. The certification suite requires a GET /v1/status endpoint that returns name, version, protocol, status, devices count, and audit_entries count. The existing code uses Fastify. Please add this endpoint following the same patterns already in the file."&lt;/p&gt;

&lt;p&gt;Copilot read the existing file, identified the right variable names (registry, auditLog, VERSION, PROTOCOL), and generated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;javascript// GET /v1/status
app.get('/v1/status', async () =&amp;gt; ({
  name:          'DoSync Hub',
  version:       VERSION,
  protocol:      PROTOCOL,
  status:        'running',
  devices:       registry.size,
  audit_entries: auditLog.length,
}))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Correct variable names. Correct Fastify pattern. No hallucinations. The key was giving Copilot the right context: the spec requirement, the existing code pattern, and the constraint. It didn't need to invent — it needed to synthesize what was already there.&lt;br&gt;
After accepting the suggestion, the certification run went from 0/11 to 11/11. GitHub Copilot helped close the gap between "protocol with one implementation" and "protocol with a certified standard."&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
License: Apache 2.0&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
    </item>
    <item>
      <title>Why AI Agents and IoT Protocols Speak Different Languages</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Tue, 26 May 2026 13:21:13 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/why-ai-agents-and-iot-protocols-speak-different-languages-831</link>
      <guid>https://dev.to/giulianiregspec/why-ai-agents-and-iot-protocols-speak-different-languages-831</guid>
      <description>&lt;p&gt;There's a distinction that comes up constantly when designing systems that connect AI to physical environments, and it's one that most protocols blur or ignore entirely.&lt;br&gt;
The distinction is between an event and an intent.&lt;br&gt;
They look similar on the surface. Both are messages. Both carry information about the world. But they describe fundamentally different things — and building a system that confuses them leads to brittleness, fragility, and automation that breaks exactly when it matters most.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What an event is&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;An event is a description of something that happened.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;json{
  "device": "pir-sensor-01",
  "type": "motion_detected",
  "timestamp": 1748000000,
  "location": "entrance"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An event is past tense. It's factual. It carries no opinion about what should happen next. The PIR sensor doesn't know whether this motion means "the kids just got home" or "there's an intruder" or "the cat walked by again." It just observed something and reported it asynchronously — fire and forget.&lt;br&gt;
Events are the raw material of a physical system. Sensors generate them constantly — temperature readings, contact closures, power measurements, motion pulses. They are objective and dumb, in the best possible sense.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What an intent is&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;An intent is a description of something that needs to happen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;json{
  "intent": "children_arrived_home",
  "urgency": "info",
  "context": {
    "trigger": "motion_detected",
    "time": "18:45",
    "day": "monday"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An intent is future tense. It carries meaning. It encodes a goal — what the system should achieve — without specifying how to achieve it. The intent doesn't say "turn on lights 3, 7, and 9 at 80% brightness." It says "the kids are home." The infrastructure figures out the rest.&lt;/p&gt;

&lt;p&gt;The leap from event to intent requires reasoning. Something has to look at the motion event, consider the time, the day, the history, and decide: this event means the kids just arrived. That reasoning is exactly what AI agents are good at.&lt;/p&gt;

&lt;p&gt;Concretely, that transition looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PIR fires motion_detected at 18:45 on Monday]
        ↓
  AI agent reasons:
  - time: 18:45 → within arrival window
  - day: Monday → weekday
  - location: entrance → consistent with arrival
        ↓
  fires: children_arrived_home [info]
        ↓
  hub resolves against device registry:
  → 5 lights turn on
  → SMS sent to parents
  → audit log updated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent handled the meaning. The protocol handled the coordination.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why conflating the two breaks systems&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Most smart home platforms today — Home Assistant automations, Matter scenes, Zigbee rules — are built on a hidden assumption: that the translation from event to action is a simple, static mapping.&lt;br&gt;
IF motion_detected AND time &amp;gt; 18:00 AND day IN [Mon, Tue, Wed, Thu, Fri]&lt;br&gt;
THEN turn_on(light_1), turn_on(light_2), send_sms("kids home")&lt;br&gt;
This works until it doesn't. Add a new light and the rule doesn't know about it. Change the schedule and you rewrite rules. Move to a new home with different devices and you start over. The rule hardcodes both the reasoning ("this motion means the kids arrived") and the execution ("these specific lights, this specific message").&lt;br&gt;
Separating events from intents breaks this coupling.&lt;br&gt;
The AI agent handles the reasoning layer: event → intent. It observes the motion, considers the context, and decides what's happening. That reasoning can be as simple or as sophisticated as needed — a time-based rule, a learned pattern, or a full LLM inference.&lt;br&gt;
The protocol handles the execution layer: intent → actions. Once the intent is declared, every device that registered as relevant participates automatically. Add a new light and it joins the response. Remove a device and the system adapts. No rules to rewrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why this matters beyond the home&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The event/intent separation is not a smart home concept. It's an architectural pattern for any system where AI needs to act on physical infrastructure.&lt;br&gt;
&lt;strong&gt;In a factory:&lt;/strong&gt; a temperature sensor fires threshold_exceeded on a critical component — that's an event. The AI reasons about it: abnormal reading, production line active, no scheduled maintenance — and determines execute_safe_shutdown. That's an intent. The execution is then coordinated automatically across the line: equipment powers down in sequence, the supervisor is paged, a maintenance request is logged, cooling activates. None of those responses were hardcoded for that specific sensor reading. Each system declared what it could do, and the protocol assembled the response.&lt;br&gt;
The pattern is always the same: the AI reasons about meaning, the infrastructure handles coordination. The temperature sensor does not know about the cooling system. The cooling system does not know about the sensor. The protocol coordinates both.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How DoSync implements this separation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In DoSync, the separation is structural. Events flow in from sensors and adapters — raw, factual, carrying no prescription. Intents flow out from AI agents — meaningful, goal-oriented, carrying no implementation.&lt;br&gt;
The hub sits in between: it receives intents, resolves them against every device's declared Capability Manifest, and builds an action plan at runtime. The resolver never sees the original event. The sensor never sees the resulting actions. The layers are cleanly decoupled.&lt;br&gt;
That decoupling is what makes the system extensible by design. A new device joins the network, declares its capabilities, and automatically participates in every relevant intent — without any rule being written, without any configuration being changed.&lt;br&gt;
That's the architectural difference that matters.&lt;/p&gt;

&lt;p&gt;DoSync Protocol: &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
License: Apache 2.0&lt;/p&gt;

</description>
      <category>iot</category>
      <category>ai</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why AI Agents Like Hermes Need a Semantic Execution Layer for the Physical World</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Sat, 23 May 2026 16:20:14 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/why-ai-agents-like-hermes-need-a-semantic-execution-layer-for-the-physical-world-1985</link>
      <guid>https://dev.to/giulianiregspec/why-ai-agents-like-hermes-need-a-semantic-execution-layer-for-the-physical-world-1985</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hermes-agent-2026-05-15"&gt;Hermes Agent Challenge&lt;/a&gt;: Write About Hermes Agent&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most AI agents interact with the world through APIs, databases, and web services. The feedback loop is fast and forgiving — if something goes wrong, you retry.&lt;br&gt;
Physical environments are different. A light that turns on twice isn't a problem. A door that unlocks at the wrong time is. An agent operating in the physical world needs not just reasoning capability, but a clear contract between what it decides and what actually executes.&lt;br&gt;
This post is about that contract — and why Hermes Agent's architecture makes it a natural fit for physical systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes Hermes Agent relevant here&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hermes Agent has three characteristics that matter specifically for physical environments:&lt;br&gt;
Native MCP support. Hermes connects to external systems via Model Context Protocol natively. Any hub or device layer that exposes an MCP server becomes immediately accessible — no custom integrations, no bridges.&lt;br&gt;
Multi-step tool use with context. Hermes doesn't just call tools — it reasons about which tool to call, in what order, based on context. For physical systems where the right action depends on time, location, and state, this matters.&lt;br&gt;
Open weights and local execution. Physical environments often have strict privacy requirements. A system that can run fully local — without sending home sensor data to a cloud provider — is architecturally different from one that can't.&lt;br&gt;
These three properties together describe an agent that can act on physical systems in a way that's both capable and auditable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The gap it needs to cross&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every physical device protocol was designed around one assumption: a human decides what to do, and a device executes it. The protocols speak in commands — lock.unlock(), light.set_brightness(100).&lt;br&gt;
An AI agent doesn't produce commands. It produces understanding. "The kids just arrived home" is not a command. The translation from that understanding to the right set of device actions — for the specific devices available, in the right context — still has to be written by someone, in advance.&lt;br&gt;
This is where most physical AI integrations break down. The agent reasons correctly and the devices exist, but the translation layer between them is a pile of hardcoded rules that grows more fragile with every new device.&lt;br&gt;
A semantic execution layer inverts this. Instead of the agent knowing how to act, devices declare what they can do and when they're relevant. The agent expresses goals. The infrastructure handles translation at runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An experiment: Hermes + DoSync&lt;/strong&gt;&lt;br&gt;
I tested this with DoSync Protocol, an open-source hub (Apache 2.0) that implements this semantic layer. Devices register with a capability manifest. The hub exposes a native MCP server.&lt;br&gt;
Connecting Hermes to DoSync required three lines in &lt;code&gt;~/.hermes/config.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;yaml&lt;/span&gt;
&lt;span class="na"&gt;mcp_servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dosync&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;/path/to/dosync/mcp_server.py&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DOSYNC_HUB_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://localhost:47200&lt;/span&gt;
      &lt;span class="na"&gt;DOSYNC_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;token&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I gave Hermes a single prompt:&lt;br&gt;
&lt;em&gt;It's 18:45 on a Monday. The PIR sensor at the entrance just detected motion.&lt;/em&gt;&lt;br&gt;
What does the system do?&lt;/p&gt;

&lt;p&gt;Hermes queried the hub state, reasoned about the time and day, identified the appropriate semantic intent (children_arrived_home), and fired it once. Five physical lights turned on. An SMS was sent to the family. The audit log updated with two new SHA-256 chained entries.&lt;br&gt;
What Hermes didn't need to know: which specific bulbs to address, the SMS provider, or the schedule policy restricting this intent to weekday evenings. That knowledge lived in the hub. Hermes expressed a goal — the infrastructure handled execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The open question&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This experiment raises a boundary question that physical AI deployments will have to answer: where does agent reasoning end and infrastructure policy begin?&lt;br&gt;
Should Hermes decide which intent to fire, or should context mapping be pre-configured? When an agent acts in a physical environment with real consequences, how much autonomy is appropriate before a human needs to confirm?&lt;br&gt;
Hermes Agent's transparency — open weights, observable tool calls, local execution — makes it the right kind of system to explore these questions. You can see exactly what it reasoned and why. In physical environments, that auditability isn't a nice-to-have. It's a requirement.&lt;/p&gt;

&lt;p&gt;DoSync Protocol (open source): &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
Hermes Agent: &lt;a href="https://hermes-agent.nousresearch.com" rel="noopener noreferrer"&gt;https://hermes-agent.nousresearch.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hermesagentchallenge</category>
      <category>devchallenge</category>
      <category>agents</category>
      <category>ai</category>
    </item>
    <item>
      <title>Why Hardcoded Automations Fail AI Agents</title>
      <dc:creator>Rodrigo Giuliani</dc:creator>
      <pubDate>Fri, 22 May 2026 12:39:00 +0000</pubDate>
      <link>https://dev.to/giulianiregspec/why-hardcoded-automations-fail-ai-agents-3b00</link>
      <guid>https://dev.to/giulianiregspec/why-hardcoded-automations-fail-ai-agents-3b00</guid>
      <description>&lt;p&gt;DoSync Concepts — Part 2 of 5&lt;/p&gt;

&lt;p&gt;There's a rule every smart home developer has written at least once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;motion_detected&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;turn_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hallway_light&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works. It's simple. And it's the foundation of how every major home automation platform thinks about intelligence today.&lt;br&gt;
The problem isn't that the rule is wrong. The problem is what happens when you add an AI agent to the system — and why rules, no matter how many you write, are the wrong abstraction for that job.&lt;/p&gt;

&lt;p&gt;The rule-writing problem&lt;br&gt;
Rules are commands in disguise. "If X happens, do Y" is just a delayed command — the human still decided what Y should be, they just decided it in advance.&lt;br&gt;
That works perfectly when you can anticipate every scenario, your device set never changes, and the AI's job is simply to trigger pre-approved responses. None of those assumptions hold in a real AI-augmented environment.&lt;br&gt;
Consider what happens when you add a new device. A smart lock arrives. You register it with your platform. Now you have to go back through every relevant rule and add the lock. Miss one and the system silently does nothing in exactly the scenario where you needed it most.&lt;br&gt;
Or consider an AI that detects unusual temperature patterns in the kitchen — a sensor reading that might mean the fridge compressor is failing. The AI knows something is wrong. But there's no rule for "fridge compressor anomaly," because nobody wrote one. The system does nothing.&lt;br&gt;
This is the brittleness problem: hardcoded automations only respond to situations that were anticipated when the rule was written.&lt;/p&gt;

&lt;p&gt;Why AI agents make this worse, not better&lt;br&gt;
The intuitive solution is to write more rules, or smarter rules. Use the AI to generate them. Inspect logs and auto-suggest new automations.&lt;br&gt;
But this misses the architectural problem.&lt;br&gt;
An AI agent doesn't produce rules. It produces understanding. When a vision model detects a fall, it doesn't know it needs to call phone.call("911") and lock.unlock() and alarm.activate("emergency"). It knows there's an emergency. The translation from understanding to commands still has to be written somewhere — by someone — in advance.&lt;br&gt;
The more capable the AI, the more situations it can detect. And every new situation the AI can detect is a new set of rules that needs to be written to respond to it. The rule surface grows faster than anyone can maintain it.&lt;/p&gt;

&lt;p&gt;What capability-based discovery changes&lt;br&gt;
The alternative is to shift where the knowledge lives.&lt;br&gt;
Instead of centralizing the response logic in rules, distribute it to the devices themselves. Each device declares what it can do and in what contexts it's appropriate to act:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;json&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"device_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lock-frontdoor-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"door-lock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"entrance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"emergency"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actuators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"unlock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"emergency_capable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"emergency_capable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This manifest is not a rule. It's a declaration. The device is saying: I can unlock. I'm relevant in emergencies. I'm at the entrance.&lt;br&gt;
When the AI fires a semantic intent — ensure_safety / emergency — the resolver reads every registered manifest and asks: which devices declared themselves relevant to this situation? It builds the response at runtime, from what's actually available.&lt;br&gt;
ensure_safety [emergency]&lt;br&gt;
  → lock-frontdoor-01    unlock   (emergency_capable, entrance tag)&lt;br&gt;
  → alarm-main-01        activate (emergency_capable)&lt;br&gt;
  → wiz-living-01..10    turn_on  (light tag, full brightness)&lt;br&gt;
  → notifier-sms-01      notify   (communication tag)&lt;br&gt;
All in parallel. No rules written for this scenario.&lt;br&gt;
Add the smart lock tomorrow — it participates automatically in every relevant scenario. No rule rewriting. No code changes. The device brought its own knowledge.&lt;/p&gt;

&lt;p&gt;The difference that matters&lt;br&gt;
Hardcoded automations are fragile because they encode knowledge in a central place that can't keep up with change. Every new device, every new scenario, every new AI capability requires human intervention to update the rules.&lt;br&gt;
Capability-based discovery distributes that knowledge to the edges. Devices own their context. The system is resilient to change because adding new capabilities is additive, not a rewrite.&lt;br&gt;
For AI agents specifically, this is the difference between a system that only responds to situations you anticipated and a system that responds to situations the AI can detect — whether you anticipated them or not.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/giulianireg-spec/dosync-protocol" rel="noopener noreferrer"&gt;https://github.com/giulianireg-spec/dosync-protocol&lt;/a&gt;&lt;br&gt;
License: Apache 2.0&lt;/p&gt;

&lt;p&gt;DoSync Concepts is a series exploring the ideas behind the DoSync Protocol — the semantic layer between AI agents and physical systems.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>ai</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
