<?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: Arcships</title>
    <description>The latest articles on DEV Community by Arcships (@dim_team).</description>
    <link>https://dev.to/dim_team</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%2F3506163%2F573ad455-2227-45c5-aaf5-09b88a7f8cae.png</url>
      <title>DEV Community: Arcships</title>
      <link>https://dev.to/dim_team</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dim_team"/>
    <language>en</language>
    <item>
      <title>How Dim Gives AI Agents an Input Guide: Meta Prompts, State, and Timeline</title>
      <dc:creator>Arcships</dc:creator>
      <pubDate>Tue, 10 Nov 2026 07:13:34 +0000</pubDate>
      <link>https://dev.to/dim_team/how-dim-gives-ai-agents-an-input-guide-meta-prompts-state-and-timeline-1f1n</link>
      <guid>https://dev.to/dim_team/how-dim-gives-ai-agents-an-input-guide-meta-prompts-state-and-timeline-1f1n</guid>
      <description>&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%2Fkggwjshrjzd1l0bo9d83.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkggwjshrjzd1l0bo9d83.png" alt="Meta Prompt: an English comic cover for Dim's input guide" width="799" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By &lt;a href="https://x.com/imwritingbugs" rel="noopener noreferrer"&gt;duskzhen&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Just after midnight on November 3, at 00:00:22, a local Dim session appended the day's date state. By the next model call, both dates appeared in the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dim-state&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"dim/environment/date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;2026-11-02&lt;span class="nt"&gt;&amp;lt;/dim-state&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dim-state&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"dim/environment/date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;2026-11-03&lt;span class="nt"&gt;&amp;lt;/dim-state&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The requests on either side of midnight (&lt;code&gt;main #1910&lt;/code&gt; and &lt;code&gt;#1930&lt;/code&gt;) used the same System Prompt. The new date arrived in the messages, while the old date remained in the history. How should the model know which one means &lt;em&gt;today&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;The answer is Dim's &lt;strong&gt;Meta Prompt&lt;/strong&gt;: an input guide supplied with each request in the Rust implementation. Its System section has a direct title, &lt;code&gt;How to read your input&lt;/code&gt;. One of its rules says that a later state from the same source supersedes the earlier current value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why send environment state separately?
&lt;/h2&gt;

&lt;p&gt;If today's date were inserted directly into the System Prompt, crossing midnight would require a new System version. The date, runtime environment, and available skills change on different schedules. Binding those values to the rules for interpreting them would force the prefix to change whenever any value changed.&lt;/p&gt;

&lt;p&gt;Dim separates the instructions for &lt;em&gt;reading&lt;/em&gt; an input from the input itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System&lt;/strong&gt; tells the model how to interpret state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messages&lt;/strong&gt; carry current values with their sources; updates have their own source and order.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To investigate the environment of an earlier request, you can follow the Timeline back to the inputs used at that point. &lt;a href="https://github.com/arcships/dim/blob/d97bd00688dfcfa6be0956ee9c372737f25f7499/crates/dim-agent-capabilities/src/prompt_guide.rs#L24-L42" rel="noopener noreferrer"&gt;Input guide and state definitions&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  If both messages have the &lt;code&gt;user&lt;/code&gt; role, who said what?
&lt;/h2&gt;

&lt;p&gt;Consider another recorded sequence. A background command finished, Dim recorded &lt;code&gt;exec/ended&lt;/code&gt; at &lt;code&gt;#413&lt;/code&gt;, then wrote a notification containing &lt;code&gt;&amp;lt;dim-notification&amp;gt;&lt;/code&gt; at &lt;code&gt;#414&lt;/code&gt;. Once consumed, that notification appeared in the model request at &lt;code&gt;#421&lt;/code&gt; with the API role &lt;code&gt;user&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The human operator's own words also use the &lt;code&gt;user&lt;/code&gt; role. The role alone cannot distinguish them. Dim sends the notification as a separate message with a runtime marker, and the guide explains its origin and meaning. A background completion notice is a result of earlier work; the model should relate it to its current task and decide whether it needs to read the full output. &lt;a href="https://github.com/arcships/dim/blob/d97bd00688dfcfa6be0956ee9c372737f25f7499/crates/dim-agent-capabilities/src/history.rs#L452-L481" rel="noopener noreferrer"&gt;Message projection implementation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Branches follow the same principle. In another recorded sequence, a child timeline inherited the main timeline's history through &lt;code&gt;#97&lt;/code&gt;. Its first model request contained both the inherited messages and a newly written branch identity block. That block also arrived in a &lt;code&gt;user&lt;/code&gt; message; the guide explained that it described the current timeline.&lt;/p&gt;

&lt;p&gt;One agent can have several timelines. The model needs an input that tells it which one it is on.&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%2Fqkmr4af0widgaschfo9h.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqkmr4af0widgaschfo9h.png" alt="English comic diagram showing eight parts of Dim's model input, from the System prefix and rules to compressed context and the input guide" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagram divides the model's input into eight categories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;System prefix&lt;/li&gt;
&lt;li&gt;Rules and state&lt;/li&gt;
&lt;li&gt;Tool declarations&lt;/li&gt;
&lt;li&gt;Runtime inputs&lt;/li&gt;
&lt;li&gt;User inputs&lt;/li&gt;
&lt;li&gt;Tool results&lt;/li&gt;
&lt;li&gt;Compressed context&lt;/li&gt;
&lt;li&gt;Input guide&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;State describes the current situation. Rules have their own scopes. Files, web pages, and command output returned by tools are material for the model to analyze. The guide explains how to read each kind of input. Runtime permission checks still happen in the runtime: &lt;strong&gt;a marker identifies a source; it does not grant authority&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who writes the guide for a new plugin?
&lt;/h2&gt;

&lt;p&gt;Take background execution as an example. The capability that produces a notification also registers the explanation for that notification. Prompt combines shared guidance with the entries applicable to the current branch. A plugin registers its explanation when loaded and withdraws it when unloaded. Once the configuration adopts the change, subsequent requests use the updated guide.&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%2Fglvqknmvv19xdyfhfogp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fglvqknmvv19xdyfhfogp.png" alt="English flowchart showing one main timeline, three model calls, a stable guide, changing messages, and context compaction" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Three model calls on the &lt;code&gt;main&lt;/code&gt; branch of one session. The blue sections show the guide delivered in System each time; the message excerpts show a date update, a branch message, a background notification, and compacted context.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This matches the way Dim assembles capabilities with rutis. When a new capability sends messages to the model, its developer can maintain the marker, meaning, and explanation in the same component. Core owns the shared reading rules; each capability owns the content it introduces. &lt;a href="https://github.com/arcships/dim/blob/d97bd00688dfcfa6be0956ee9c372737f25f7499/crates/dim-agent-capabilities/src/prompt_guide.rs#L125-L208" rel="noopener noreferrer"&gt;Guide registration and composition&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What can the model understand with this guide?
&lt;/h2&gt;

&lt;p&gt;The Meta Prompt does more than explain one message. It helps the model maintain an accurate picture of its environment. Follow the &lt;code&gt;main&lt;/code&gt; Timeline in the diagram above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configuration:&lt;/strong&gt; Prompt combines the shared guidance and registered plugin entries into Guide A. At &lt;code&gt;context/configured&lt;/code&gt;, that guide is adopted in System.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request 1:&lt;/strong&gt; Messages include a project rule (&lt;code&gt;&amp;lt;dim-rule&amp;gt;&lt;/code&gt;) and the current date (&lt;code&gt;&amp;lt;dim-state&amp;gt;&lt;/code&gt;). The model can see both the rule it should follow and the date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request 2:&lt;/strong&gt; A date update (&lt;code&gt;&amp;lt;dim-state&amp;gt;&lt;/code&gt;), branch message (&lt;code&gt;&amp;lt;dim-branch-message&amp;gt;&lt;/code&gt;), and background notification (&lt;code&gt;&amp;lt;dim-notification&amp;gt;&lt;/code&gt;) arrive in order. The model can tell that time has advanced, another timeline has sent a message, and a task has finished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request 3, after compaction:&lt;/strong&gt; A history summary (&lt;code&gt;&amp;lt;dim-summary&amp;gt;&lt;/code&gt;) and tool digest (&lt;code&gt;&amp;lt;dim-digest&amp;gt;&lt;/code&gt;) replace older detail, while currently effective rules and state are reaffirmed. The model can distinguish past events from conditions that still apply.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three requests use Guide A in System. The Messages change. The reading rules stay stable while the environment moves through the input stream.&lt;/p&gt;

&lt;p&gt;In concrete terms, the model can track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time:&lt;/strong&gt; which date is current, without mistaking an earlier date for today.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules:&lt;/strong&gt; which project rules still apply and what their scopes are.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Position:&lt;/strong&gt; which branch and timeline it is on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events:&lt;/strong&gt; whether a background command finished or another timeline sent a message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;History:&lt;/strong&gt; after compaction, what happened earlier and what still governs the present.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are no longer stray lines mixed into a conversation. They form an account of the environment with a source, an order, and a reading guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do rules change midway through a session?
&lt;/h2&gt;

&lt;p&gt;So far, the examples have started from an already configured guide. In a real session, a plugin can be enabled or disabled midway, and rules can become active or expire. Two questions need separate answers: &lt;strong&gt;how should the model read a kind of content, and which specific content is currently effective?&lt;/strong&gt; Dim handles those through different channels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading rules: register with a plugin, withdraw with it
&lt;/h3&gt;

&lt;p&gt;When a plugin is enabled:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It registers the markers it will emit, their meanings, and their explanations.&lt;/li&gt;
&lt;li&gt;Prompt recombines the shared guidance with those entries into a new guide.&lt;/li&gt;
&lt;li&gt;After configuration adoption (&lt;code&gt;context/configured&lt;/code&gt;), subsequent requests use the new System.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Disabling it reverses the sequence: the plugin unloads, its explanation is withdrawn, Prompt recombines the guide, and later requests stop carrying that explanation.&lt;/p&gt;

&lt;p&gt;This ordering puts the explanation in place before the content appears. It also prevents the model from continuing to interpret new input using withdrawn guidance. Earlier requests are not rewritten; the Timeline still records which guide version each one used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Current content: append new rules, expire old ones within their scope
&lt;/h3&gt;

&lt;p&gt;Rules and state do not rewrite history either. They are appended. The &lt;code&gt;op&lt;/code&gt; on a &lt;code&gt;&amp;lt;dim-rule&amp;gt;&lt;/code&gt; describes what happens to that rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;set&lt;/code&gt; or &lt;code&gt;replace&lt;/code&gt; makes the rule in the block effective; &lt;code&gt;replace&lt;/code&gt; identifies the currently adopted version.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;revoke&lt;/code&gt; or &lt;code&gt;expired&lt;/code&gt; makes that rule ineffective within its scope. A rule with the same name in another scope is unaffected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;State is simpler: a later value from the same source supersedes an earlier one. A state block with &lt;code&gt;cleared="true"&lt;/code&gt; says that state no longer applies.&lt;/p&gt;

&lt;p&gt;Adding a rule during a session means appending an effective block. Removing one means appending a block that marks it ineffective. The old block remains in history; the model uses the latest block for the same source and scope. The two dates at the start of this article work the same way.&lt;/p&gt;

&lt;h3&gt;
  
  
  After compaction, expired rules stay expired
&lt;/h3&gt;

&lt;p&gt;When compaction happens, subsequent state blocks reaffirm only the rules and state still effective at that moment. Each is restated in its most recently delivered form, such as a &lt;code&gt;replace&lt;/code&gt; block for the adopted rule version. A revoked rule is absent, so the model does not treat it as current again. The guide also says these reaffirmations confirm the current situation: they are not new changes and do not grant permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which state survives compaction?
&lt;/h2&gt;

&lt;p&gt;Return to the session that crossed midnight. Later, &lt;code&gt;#2025&lt;/code&gt; recorded a successful context compaction. The next model request, &lt;code&gt;#2026&lt;/code&gt;, carried the summary and then reaffirmed five rules and state values still effective at that point. Of the two dates, only November 3 remained as current state.&lt;/p&gt;

&lt;p&gt;The two parts have different jobs. The summary describes what happened before; the subsequent state blocks describe the conditions the model should keep working under. The input guide explains that these restatements mean the earlier rules and state are &lt;em&gt;still effective&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To see exactly what a model received at a given moment, return to that request and compare its adopted guide, state, and retained history. &lt;a href="https://github.com/arcships/dim/blob/d97bd00688dfcfa6be0956ee9c372737f25f7499/crates/dim-agent-capabilities/src/history.rs#L833-L873" rel="noopener noreferrer"&gt;Post-compaction message projection&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Editorial note: AI tools assisted with the English adaptation and illustrations.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>architecture</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Timelines, Bike Theft, and the Art of Designing Dim: Event-Driven Architecture for AI Agents</title>
      <dc:creator>Arcships</dc:creator>
      <pubDate>Tue, 10 Nov 2026 06:43:10 +0000</pubDate>
      <link>https://dev.to/dim_team/timelines-bike-theft-and-the-art-of-designing-dim-event-driven-architecture-for-ai-agents-1go3</link>
      <guid>https://dev.to/dim_team/timelines-bike-theft-and-the-art-of-designing-dim-event-driven-architecture-for-ai-agents-1go3</guid>
      <description>&lt;p&gt;&lt;em&gt;By &lt;a href="https://x.com/imwritingbugs" rel="noopener noreferrer"&gt;duskzhen&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Imagine I park my bike outside my front door. Worried it might get stolen, I set up a security camera and hire an AI Agent:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Keep an eye on my bike for me."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A naive implementation is to have the Agent poll the camera feed every few seconds:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bike is still there. Bike is still there. Bike is still there. Someone walked past. Bike is still there.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By morning, the bike is safe—and the context window is completely blown.&lt;/p&gt;

&lt;p&gt;Sure, that approach &lt;em&gt;works&lt;/em&gt;. But what I actually need is for someone to notice when the bike might be in danger, review what happened, and decide what to do next. Eight hours of peace and quiet on the street shouldn't translate into eight hours of continuous LLM inference.&lt;/p&gt;

&lt;p&gt;While designing &lt;strong&gt;&lt;a href="https://github.com/arcships/dim" rel="noopener noreferrer"&gt;Dim&lt;/a&gt;&lt;/strong&gt;, we came back to this scenario so often that we started calling it our &lt;strong&gt;"Bike Theft Theory."&lt;/strong&gt; It illustrates a simple core principle: &lt;strong&gt;Just because the environment is constantly changing doesn't mean the model needs to be constantly thinking.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Camera Records; the Agent Checks on Demand
&lt;/h2&gt;

&lt;p&gt;Let's try a different setup.&lt;/p&gt;

&lt;p&gt;The camera records continuously. Meanwhile, the Agent can work on other tasks or simply wait idle. At some point, a lightweight motion detector notices someone approaching the bike and fires a notification.&lt;/p&gt;

&lt;p&gt;Only then does the Agent pull up the relevant video clips: &lt;em&gt;When did this person arrive? Did they just walk past, or are they tampering with the lock? Has the bike moved?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After inspecting the footage, the Agent might realize it's just a neighbor picking up something they dropped. It logs that assessment and goes back to waiting. Or, it might see the lock being cut and alert the owner using a pre-agreed method.&lt;/p&gt;

&lt;p&gt;Here, the notification's only job is to say, &lt;em&gt;"Something happened that's worth looking into."&lt;/em&gt; &lt;strong&gt;Someone approaching is a clue; whether they are stealing the bike requires looking at the evidence.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6seltavqv0tyc3c5jkkt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6seltavqv0tyc3c5jkkt.gif" alt="Bike anti-theft concept: the camera records continuously, fires a notification when someone approaches, and the Agent reviews the relevant clips on demand" width="720" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Four-act conceptual animation: record, detect change, notify, and review on demand. (Bike surveillance is a hypothetical scenario used to explain our runtime architecture, not a built-in camera feature in Dim.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What if the detector misses something? The owner might walk out the next morning, see the bike is gone, and ask: &lt;em&gt;"What happened last night?"&lt;/em&gt; As long as the underlying records exist, the Agent can work backward from that question and inspect the past.&lt;/p&gt;

&lt;p&gt;To pull this off, the system has to solve two distinct problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Leave behind records that might be needed later.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pull the Agent's attention over at the right moment.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without the first, an alarm goes off and there's no way to investigate what happened. Without the second, you end up with a hard drive full of footage that nobody ever looks at.&lt;/p&gt;

&lt;p&gt;This exact division of labor is where Dim's &lt;strong&gt;Timeline&lt;/strong&gt; and &lt;strong&gt;Event-Driven Architecture&lt;/strong&gt; begin.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Chat History Alone Isn't Enough
&lt;/h2&gt;

&lt;p&gt;When I previously worked on DeepChat, I was inspired by the "Tape" mental model: treating Context as an append-only tape. User prompts, model responses, and tool outputs all move forward along a single track. That gives you a solid foundation for context compression, sliding windows, and branching.&lt;/p&gt;

&lt;p&gt;With Dim, we wanted to take a step further outside the chat box.&lt;/p&gt;

&lt;p&gt;The environment an Agent lives in is much busier than a simple request-response loop. Background commands finish on their own, other branches send messages, the system date rolls over, plugins load, and users change their minds while a tool is still mid-execution.&lt;/p&gt;

&lt;p&gt;Some of these changes demand an immediate reaction. Others just need to be logged for posterity, or queued until the current task wraps up. We can't pretend these events didn't happen just because the model wasn't looking—nor can we dump every single environmental change straight into the model's prompt.&lt;/p&gt;

&lt;p&gt;Going back to the bike: &lt;em&gt;"The camera recorded this footage"&lt;/em&gt; and &lt;em&gt;"The Agent watched this footage"&lt;/em&gt; are fundamentally different facts.&lt;/p&gt;

&lt;p&gt;Dim's &lt;strong&gt;Timeline&lt;/strong&gt; bakes this distinction directly into the runtime. It records operational events across tasks that affect subsequent behavior, while the model's context is projected selectively from facts like inputs, outputs, tool results, and context states. &lt;strong&gt;The scope of what's recorded on the Timeline is intentionally broader than what the model sees in any single inference request.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And "recording the environment" doesn't mean dumping the entire world raw into a database. In our bike setup, heavy video files stay in blob storage while the Timeline records clip indices, detection events, and follow-up actions. In Dim, the key is recording the operational facts needed for coordination, auditing, and recovery—while reading the heavy raw materials on demand.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Timeline: Giving Every Event a Deterministic Place
&lt;/h2&gt;

&lt;p&gt;The word "Timeline" might sound like a simple timestamped log. In Dim, however, it defines the canonical execution order of the runtime.&lt;/p&gt;

&lt;p&gt;Every branch has its own Timeline. As events are appended, the Timeline assigns a monotonically increasing &lt;code&gt;sequence&lt;/code&gt; number. The runtime understands causality and order strictly through this sequence; a wall clock can tell a human &lt;em&gt;when&lt;/em&gt; something happened, but it cannot replace the deterministic order of the sequence.&lt;/p&gt;

&lt;p&gt;Why does this matter?&lt;/p&gt;

&lt;p&gt;Suppose you tell the Agent, &lt;em&gt;"Forget about the bike for now,"&lt;/em&gt; right as a slow background detector finally returns &lt;em&gt;"Someone is approaching."&lt;/em&gt; The system needs to know which task that detection belongs to and exactly where the cancellation command sits in the sequence so it can apply the right rules. Relying on whichever async callback finishes first is a recipe for resurrecting canceled tasks.&lt;/p&gt;

&lt;p&gt;In our bike analogy, the Timeline 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;Records append continuously →

Park Bike ── Clip Index ── Approach Detected ── Notification ── Read Clip ── Verdict
                                  │                                 ▲
                                  └─── Draws Attention ─────────────┘

Raw footage stays in storage for later review; the current judgment only fetches the relevant clip.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New conclusions don't overwrite old facts, either. First we record &lt;em&gt;"Approach Detected,"&lt;/em&gt; and later we record &lt;em&gt;"Confirmed just passing by."&lt;/em&gt; We know both the current state of the world and the exact reasoning trail that got us there.&lt;/p&gt;

&lt;p&gt;In code, this ordering comes with a strict persistence guarantee: in the SQLite storage path used by the App Server, the Timeline only advances its published cursor &lt;em&gt;after&lt;/em&gt; an event batch is successfully committed to disk, which in turn allows the Dispatcher to broadcast them. Returning from &lt;code&gt;append&lt;/code&gt;, committing to storage, and publishing to subscribers are explicitly distinct phases (see &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/crates/dim-agent-runtime/src/core/timeline.rs#L392-L521" rel="noopener noreferrer"&gt;Timeline commit and publish implementation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This ensures every subsequent reaction is grounded in verifiable history. Records aren't just for post-mortem debugging—they actively drive how the system moves forward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Event-Driven Runtime: Only Wake Up What Needs to Move
&lt;/h2&gt;

&lt;p&gt;Once you have a Timeline, something needs to consume it.&lt;/p&gt;

&lt;p&gt;Dim uses a &lt;strong&gt;Dispatcher&lt;/strong&gt; to broadcast published events in sequence. Runtime capabilities subscribe only to the event types they care about. Upon receiving an event, a capability updates its internal state or kicks off a job, writing any resulting facts back to the Timeline (see &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/crates/dim-agent-runtime/src/core/dispatcher.rs#L130-L222" rel="noopener noreferrer"&gt;Dispatcher subscription and dispatch implementation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Being "event-driven" happens first and foremost between these runtime components. &lt;strong&gt;It does not mean firing an LLM request for every single event.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the camera detects motion, a lightweight heuristic can decide if it warrants a notification; when video archiving finishes, it just updates a record; when a monitoring task is canceled, it quietly cleans up its resources. Only items that genuinely require the model's reasoning are routed into the input channel.&lt;/p&gt;

&lt;p&gt;We strictly separate three stages:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;What It Means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Record Event&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The fact has entered the auditable history.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dispatch Event&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Interested runtime capabilities can react to it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deliver to Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Relevant content has entered the model-visible context via inputs or tool results.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Recording an event does not mean the model knows about it yet.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dim's context management makes this boundary explicit: ordinary runtime events don't magically turn into LLM messages on their own. Content meant for the model must enter the context through adopted inputs or tool results. For instance, an input is first recorded as an event, and only when &lt;code&gt;input/consumed&lt;/code&gt; occurs does the history projection expand it into an actual model message (see &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/crates/dim-agent-capabilities/src/history.rs#L970-L987" rel="noopener noreferrer"&gt;Input consumption and message projection&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftkg851t0zr7joeudttt1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftkg851t0zr7joeudttt1.gif" alt="Timeline and input delivery: an event is appended and committed, the Dispatcher routes it, a capability creates a notification input, and only after the input is consumed does it enter the model context" width="720" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Using a background command completion as an example, this animation shows how an event triggers a new notification input. Arrows indicate processing causality; notifications, input consumption, and model requests themselves also leave records on the Timeline.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This gives us a two-tier filter for &lt;em&gt;"what's worth looking at."&lt;/em&gt; First, the runtime follows capability contracts to decide which environmental changes warrant delivery. Second, once delivered, the model evaluates the notification against its current goal to decide whether to inspect deeper or take action. Meanwhile, the user can step in at any time to adjust the goal or shift focus.&lt;/p&gt;




&lt;h2&gt;
  
  
  No Bike Required: Background Commands as a Real-World Example
&lt;/h2&gt;

&lt;p&gt;You don't need a physical security camera to see this in action. Consider a classic developer workflow: an Agent kicks off a long-running build or test suite in the background and moves on to other work. When that command finally finishes, how do we bring the Agent back?&lt;/p&gt;

&lt;p&gt;Dim's background execution capability follows the exact path we just described:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The command finishes, emitting an &lt;code&gt;exec/ended&lt;/code&gt; event with the execution result.&lt;/li&gt;
&lt;li&gt;Once committed and published, the Dispatcher routes the event to the background execution capability.&lt;/li&gt;
&lt;li&gt;The capability checks the exit status and branch state; if wake-up conditions are met, it appends a notification input.&lt;/li&gt;
&lt;li&gt;The notification wraps a &lt;code&gt;&amp;lt;dim-notification&amp;gt;&lt;/code&gt; tag, a short output preview, and instructions on how to fetch the full log, entering the scheduler as a &lt;code&gt;Steer&lt;/code&gt; input.&lt;/li&gt;
&lt;li&gt;Once the input is consumed, the model reads the notification in its next turn and decides what to do.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In our current implementation, canceled background tasks won't trigger a wake-up along this path, nor will branches that are in the middle of shutting down. Because the completion event and the notification input are committed separately, our crash-recovery logic also checks for completed jobs that needed a wake-up but haven't emitted a notification yet (see &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/crates/dim-agent-capabilities/src/workspace_tools/background.rs#L413-L460" rel="noopener noreferrer"&gt;Background result handling&lt;/a&gt; and &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/crates/dim-agent-capabilities/src/workspace_tools/background.rs#L674-L718" rel="noopener noreferrer"&gt;Notification input construction&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This is the exact developer equivalent of the bike scenario: the full stdout/stderr log is the recorded footage, the completion alert is the motion notification, and calling a tool to read the full log is pulling up the video clip.&lt;/p&gt;

&lt;p&gt;The model never has to spin in a loop asking, &lt;em&gt;"Is it done yet?"&lt;/em&gt; And when the command &lt;em&gt;does&lt;/em&gt; finish, it doesn't blindly force the old task to resume—if the user has already pivoted to a new goal, the Agent interprets the late-arriving result in the context of its new instructions.&lt;/p&gt;

&lt;p&gt;At this point, the Timeline handles recording and ordering, and the event-driven runtime handles reaction and scheduling. That leaves one final puzzle: &lt;strong&gt;When the model receives this text in its context, how does it know what the message actually means?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Meta Prompt: Teaching the Model How to Read Its Inputs
&lt;/h2&gt;

&lt;p&gt;In our previous post on Dim's &lt;strong&gt;Meta Prompt&lt;/strong&gt; &lt;em&gt;(An Input Manual for Models)&lt;/em&gt;, we highlighted a subtle quirk of LLM APIs: whether a piece of text is typed directly by a human operator or injected as a notification by the runtime, it often arrives at the model API wearing the exact same &lt;code&gt;user&lt;/code&gt; role.&lt;/p&gt;

&lt;p&gt;If the model relies solely on the message role, it can easily confuse &lt;em&gt;"The human user just gave me a new command"&lt;/em&gt; with &lt;em&gt;"A background process from five minutes ago just exited."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The bike analogy works the same way. When the camera says &lt;em&gt;"Someone is approaching,"&lt;/em&gt; that's a sensor observation. When the owner says &lt;em&gt;"Check who was just near my bike,"&lt;/em&gt; that's an operator command. Both might point to the exact same video clip, but their origin, authority, and expected next steps are completely different.&lt;/p&gt;

&lt;p&gt;Dim's &lt;strong&gt;Meta Prompt&lt;/strong&gt; bridges this semantic gap. Alongside the system prompt, it provides an explicit "Input Guide." Each runtime capability registers the structural tags it introduces and their exact semantics, while dynamic payloads are delivered later through corresponding inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For &lt;code&gt;&amp;lt;dim-notification&amp;gt;&lt;/code&gt; (Background Alerts):&lt;/strong&gt; The guide explains that this is the result of previously initiated work, the snippet is a preview from that command, and full output can be fetched on demand—and crucially, if the parent task is obsolete, do not restart it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For &lt;code&gt;&amp;lt;dim-state&amp;gt;&lt;/code&gt;:&lt;/strong&gt; It explains state-update semantics, where newer values from the same source supersede earlier ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For &lt;code&gt;&amp;lt;dim-rule&amp;gt;&lt;/code&gt;:&lt;/strong&gt; It defines scoping and activation/deactivation lifecycles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(See &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/crates/dim-agent-capabilities/src/prompt_guide.rs#L24-L46" rel="noopener noreferrer"&gt;Input Guide implementation&lt;/a&gt; and &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/crates/dim-agent-capabilities/src/workspace_tools/background.rs#L729-L731" rel="noopener noreferrer"&gt;Background notification semantics&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Applied to our bike scenario, the model knows immediately which message is a sensor observation, which is the owner's instruction, whether bike monitoring is still active, and what countermeasures are authorized.&lt;/p&gt;

&lt;p&gt;Of course, XML tags alone don't grant security permissions, and slapping an "Alert" label on sensor data doesn't turn it into an executable command. The model uses the Input Guide to understand &lt;em&gt;meaning&lt;/em&gt;, while the runtime strictly enforces permission checks before any tool action is executed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Timeline gives events a place, the event-driven Dispatcher routes changes to the right handlers, and the Meta Prompt gives the model a framework to interpret them.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Making the Entire Harness Part of the Intelligence
&lt;/h2&gt;

&lt;p&gt;Now, let's wire all these pieces together.&lt;/p&gt;

&lt;p&gt;The environment changes, and facts are written to the Timeline. Runtime capabilities react to those events and push only what requires reasoning into the input queue. The model combines the Meta Prompt, its current objective, and its context history to make a judgment—calling tools when it needs more evidence, or triggering actions when it needs to intervene. Those tool outputs and subsequent environmental shifts then become new records on the Timeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmfic6c0esfsbfiudb6i6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmfic6c0esfsbfiudb6i6.gif" alt="Agent Harness feedback loop: environment changes, Timeline records, notification input, Meta Prompt interprets, model judgment, tool feedback, back to the Timeline" width="720" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Architectural overview: The Meta Prompt provides rules for reading inputs rather than acting as an async queue processor. The model's actions affect the environment via tools, and the results flow back into the Timeline.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When you view an &lt;strong&gt;Agent Harness&lt;/strong&gt; this way, you realize you don't have to shove every ounce of responsibility onto the LLM. Recording, ordering, scheduling, provenance tracking, and permission enforcement are handled deterministically by the runtime; the model saves its tokens and attention for synthesizing goals and evidence.&lt;/p&gt;

&lt;p&gt;This separation also makes long-horizon tasks sustainable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context Compression &amp;amp; Recall:&lt;/strong&gt; When the context window fills up, summaries carry forward the past while re-asserting active rules and states. If the model later needs fine-grained details, Dim's &lt;code&gt;recall&lt;/code&gt; tool lets it search and retrieve prior conversations and work records on demand. Compression only changes what is packed into the &lt;em&gt;current&lt;/em&gt; inference request—the underlying historical facts remain safely stored on the Timeline (see &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/docs/architecture/rust-agent/timeline-storage.md#%E5%8E%8B%E7%BC%A9%E6%A3%80%E6%9F%A5%E7%82%B9" rel="noopener noreferrer"&gt;Context compression checkpoints&lt;/a&gt; and &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/crates/dim-agent-capabilities/src/recall.rs#L1-L10" rel="noopener noreferrer"&gt;Recall tool&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent Crash Recovery:&lt;/strong&gt; Recovery respects the boundary between state and side effects. Re-reading a record that says &lt;em&gt;"Alert already sent to owner"&lt;/em&gt; restores the system's awareness that the alert was sent—it doesn't fire the alert a second time. Rebuilding internal state and re-executing external side effects have strictly separated boundaries (see &lt;a href="https://github.com/arcships/dim/blob/0423b321abc923900525d79d030fd690110f91c4/docs/architecture/rust-agent/time-bus.md#5-%E5%89%AF%E4%BD%9C%E7%94%A8%E4%B8%8D%E9%87%8D%E6%94%BE" rel="noopener noreferrer"&gt;Time-bus side-effect guarantees&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Naturally, architecture alone doesn't make detectors infallible or models immune to misjudgment. If notifications are too noisy, the Agent gets woken up constantly; if they're too sparse, critical changes slip through. And if you still end up piping every raw video frame into the prompt, calling your log a "Timeline" won't save you a single token.&lt;/p&gt;

&lt;p&gt;What's truly worth engineering is the &lt;strong&gt;coordination&lt;/strong&gt; between the runtime and the model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can past records be retrieved when needed?&lt;/li&gt;
&lt;li&gt;Do notifications provide enough clues without overwhelming the context?&lt;/li&gt;
&lt;li&gt;Does the model understand the provenance and authority of incoming messages?&lt;/li&gt;
&lt;li&gt;Does it have the evidence required to act, and does it get feedback after acting?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Back to that bike parked outside my door: I want an Agent that doesn't stare at the camera feed all night, yet snaps to attention the moment someone approaches; reviews the footage before jumping to conclusions; remembers if I've changed my mind about watching the bike; and can explain clearly the next morning what happened and why it handled things the way it did.&lt;/p&gt;

&lt;p&gt;That is the exact coordination we're building in &lt;strong&gt;Dim&lt;/strong&gt;—making sure environmental changes are reliably recorded and routed, so the model can see clearly right when it needs to.&lt;/p&gt;




&lt;p&gt;The &lt;a href="https://github.com/arcships/dim" rel="noopener noreferrer"&gt;Dim repository&lt;/a&gt; contains the Rust implementation discussed here.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Editorial note: AI tools assisted with the English adaptation and visuals.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>architecture</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Introducing dim: A Better Runtime and Body for Agents</title>
      <dc:creator>Arcships</dc:creator>
      <pubDate>Thu, 05 Nov 2026 09:24:03 +0000</pubDate>
      <link>https://dev.to/dim_team/introducing-dim-a-better-runtime-and-body-for-agents-366b</link>
      <guid>https://dev.to/dim_team/introducing-dim-a-better-runtime-and-body-for-agents-366b</guid>
      <description>&lt;p&gt;&lt;strong&gt;Today, we’re open-sourcing dim—an agent harness built around an event timeline.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We want agents to perceive their environment, revisit their history, explore in parallel, and keep making progress toward their goals.&lt;/p&gt;

&lt;p&gt;As models become more capable, agent architectures need to evolve alongside them. Our guiding principle is simple: &lt;strong&gt;fewer constraints, more guidance, and more room for models to understand, explore, and act.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That idea shapes four core architectural choices in dim.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Event Timeline at the Core
&lt;/h2&gt;

&lt;p&gt;Many agent harnesses are organized around message lists and model requests. dim is organized around a continuously growing event timeline.&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%2F2m1bpfjp93r048ilk3us.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2m1bpfjp93r048ilk3us.png" alt="An event timeline at the core of dim" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;User input, the agent’s decisions and actions, tool results, and the harness’s own operations can all become events on this timeline. Together, they record the agent’s interactions with the world and preserve the history of its ongoing work.&lt;/p&gt;

&lt;p&gt;Once written, events are immutable and dispatched for processing. The state machines that consume and handle these events are called &lt;strong&gt;capabilities&lt;/strong&gt;. Each capability advances the work it is responsible for, turning events into concrete changes and actions.&lt;/p&gt;

&lt;p&gt;The agent’s history therefore includes its observations, actions, and results alongside its conversations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perceiving the Environment and Recalling History
&lt;/h2&gt;

&lt;p&gt;We want agents to actively understand the environments they operate in.&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%2Fmdekdj5cpmlrh5x26qlr.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmdekdj5cpmlrh5x26qlr.png" alt="Environment awareness and history recall in dim" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In dim, an agent can choose to receive additional events from its environment. For example, it can learn which terminal, web interface, or client a user is interacting through, or become aware of configuration changes around it.&lt;/p&gt;

&lt;p&gt;Developers, users, and even the agent itself can define &lt;strong&gt;meta-prompts&lt;/strong&gt; to help the agent interpret what is happening.&lt;/p&gt;

&lt;p&gt;The agent can also retrieve history from across the entire timeline in a structured way, including past conversations, events, actions, and results.&lt;/p&gt;

&lt;p&gt;This richer view of its environment and history gives the agent more context for understanding tasks—and a foundation for more proactive exploration and action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring in Parallel Through Timeline Branches
&lt;/h2&gt;

&lt;p&gt;dim supports timeline branches, allowing an agent to explore, reflect, and advance multiple lines of work in parallel.&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%2Fqo7cj6hocco9chdiksul.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqo7cj6hocco9chdiksul.png" alt="Parallel exploration through timeline branches" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We call this capability &lt;em&gt;split attention&lt;/em&gt;: the same agent splitting its attention across multiple branches. Unlike subagents or collaboration across separate sessions, these branches represent the same agent thinking and working along different paths.&lt;/p&gt;

&lt;p&gt;Each branch has the same resources, isolation boundaries, and rules as the main branch. At the prompt level, the branches maintain a consistent identity as the same agent.&lt;/p&gt;

&lt;p&gt;Branching gives the agent room to examine problems from different angles and use reflection to keep advancing long-term goals. dim’s &lt;strong&gt;goal (pursuit) mode&lt;/strong&gt; is one example of this capability in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Agent’s Body with Plugins
&lt;/h2&gt;

&lt;p&gt;The model provides the ability to think. Tools, devices, and the runtime environment give the agent ways to interact with the world. We think of these capabilities as the agent’s body.&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%2Fwtz2nupkp9fhxq0z546t.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwtz2nupkp9fhxq0z546t.png" alt="Building an agent’s body with plugins" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;dim’s plugin system is built on &lt;strong&gt;rutis&lt;/strong&gt;. Developers can write plugins in TypeScript, Go, Python, Swift, Kotlin, and other languages, connecting capabilities from different ecosystems and helping the agent extend and refine its body.&lt;/p&gt;

&lt;p&gt;Plugins can run on different devices. Components such as dim’s timeline, store, and execution can also be mounted remotely, opening up more possibilities for agents running in the cloud.&lt;/p&gt;

&lt;p&gt;Looking ahead, we want mobile devices, ESP32 boards, and other hardware to be able to host an agent or one of its branches, connected through different networking stacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Start with the installation instructions in the &lt;a href="https://github.com/arcships/dim" rel="noopener noreferrer"&gt;repository README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You’ll need a Node.js version that satisfies &lt;code&gt;^22.19.0 || &amp;gt;=23.11.0&lt;/code&gt;, with npm’s optional dependencies enabled.&lt;/p&gt;

&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm install -g dimcode-alpha@alpha
dima
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once dim starts, use &lt;code&gt;login/&lt;/code&gt; to sign in or &lt;code&gt;models/&lt;/code&gt; to select a configured model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Already using dimcode?&lt;/strong&gt; The &lt;code&gt;dimcode&lt;/code&gt; package is still the existing TypeScript CLI. The Rust alpha introduced here uses a separate package, &lt;code&gt;dimcode-alpha&lt;/code&gt;, and command, &lt;code&gt;dima&lt;/code&gt;. Both can coexist, and each maintains its own data.&lt;/p&gt;

&lt;p&gt;Plugins, hooks, and MCP services can execute code when enabled. For an initial exploration, we recommend starting in read-only mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dima --permission read-only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Help Us Build It
&lt;/h2&gt;

&lt;p&gt;We’ll continue improving the code and documentation in the repository.&lt;/p&gt;

&lt;p&gt;If you run into a problem, find something unclear, or have a use case you’d like to explore, please share the details in &lt;a href="https://github.com/arcships/dim/issues" rel="noopener noreferrer"&gt;GitHub Issues&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We’ll also publish more articles and video tutorials covering setup, how dim works, and how to use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/arcships/dim" rel="noopener noreferrer"&gt;Explore the source code and getting-started guide →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building rutis: Replaceable Plugins Across Languages and Machines</title>
      <dc:creator>Arcships</dc:creator>
      <pubDate>Tue, 03 Nov 2026 06:07:41 +0000</pubDate>
      <link>https://dev.to/dim_team/building-rutis-replaceable-plugins-across-languages-and-machines-3ade</link>
      <guid>https://dev.to/dim_team/building-rutis-replaceable-plugins-across-languages-and-machines-3ade</guid>
      <description>&lt;p&gt;&lt;em&gt;By Eric Cheng · Arcships · First published in Chinese on October 23, 2026&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; rutis is a Rust-based plugin runtime for agents and other long-running software. Plugins provide named services, so a caller can keep using &lt;code&gt;calendar&lt;/code&gt; while its implementation changes language or moves to another machine. rutis tracks dependencies, cleanup, and the restart of affected plugins so those changes can happen without restarting the host.&lt;/p&gt;

&lt;p&gt;Agents can write integration code quickly. The harder question is how to try that code, replace it, and roll back failures while the system keeps running. This post explains rutis's lifecycle model, how it crosses process and machine boundaries, and where the design is headed.&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%2Fyj7xh9pevha6i9mipg5z.jpg" 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%2Fyj7xh9pevha6i9mipg5z.jpg" alt="A system connects to the capabilities around it" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. When changing code is no longer expensive
&lt;/h2&gt;

&lt;p&gt;In the past, we designed software on the assumption that changes were costly. We tried to settle requirements first, stabilize interfaces, lock down dependencies, and then change as little as possible.&lt;/p&gt;

&lt;p&gt;When changes become cheap, that assumption no longer holds. For software that can iterate on itself, the everyday activity is not simply &lt;em&gt;running&lt;/em&gt;. It is &lt;em&gt;trying things out&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Today it needs to connect to an internal calendar system, so it writes a first version and tries it.&lt;/li&gt;
&lt;li&gt;Tomorrow it finds a better interface for that system and swaps in a new version.&lt;/li&gt;
&lt;li&gt;The next day it needs a model on a GPU machine, so it moves part of its capability there.&lt;/li&gt;
&lt;li&gt;Later, a heavily used component needs to be faster and more reliable, so it is rewritten in another language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each change is small. But a running system may go through dozens of these small changes in a week.&lt;/p&gt;

&lt;p&gt;The hard part shifts from &lt;em&gt;how to write it&lt;/em&gt; to &lt;em&gt;how to keep replacing it&lt;/em&gt;. When a component is replaced, are old connections, timers, and listeners left behind? Do the components that depend on it break? Can a bad replacement be rolled back? If a service moves to another machine or is rewritten in another language, must all of its callers change too?&lt;/p&gt;

&lt;p&gt;These questions determine whether software can really grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Wait for others to adapt, or connect to them ourselves?
&lt;/h2&gt;

&lt;p&gt;Today, the usual way for software to gain a new capability is to wait for someone else to make it available.&lt;/p&gt;

&lt;p&gt;The maintainers of an environment provide an API, an SDK, an open platform, or, more recently, an MCP server. Software calls what they provide. This is a good approach, but it assumes that &lt;strong&gt;what software can do depends on what someone outside it has prepared&lt;/strong&gt;. The connection sits outside the software. It belongs to the environment, not to the software.&lt;/p&gt;

&lt;p&gt;Once software can write its own code, that assumption becomes unnecessary. It can reverse the direction of the work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It can spend its own effort connecting to and adapting to other systems.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Whatever it needs to reach, it can write a plugin to connect to it—in the language that fits best, perhaps with an agent writing the plugin. It can try, revise, and replace that plugin. The connection becomes part of the software, with its own lifecycle. It can be observed and cleanly removed.&lt;/p&gt;

&lt;p&gt;Eventually, software could even &lt;strong&gt;replace an external interface or system&lt;/strong&gt;. That may sound like a slogan, but in rutis it follows from a simple mechanism:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A consumer depends on a service's &lt;strong&gt;name&lt;/strong&gt;, not on its implementation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suppose a scheduling feature depends on a service named &lt;code&gt;calendar&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At first, a plugin provides &lt;code&gt;calendar&lt;/code&gt; by wrapping the company's existing calendar system.&lt;/li&gt;
&lt;li&gt;After real use, the team understands which methods &lt;code&gt;calendar&lt;/code&gt; needs and what they should return.&lt;/li&gt;
&lt;li&gt;Later, the provider is replaced with an in-house implementation that still exposes the name &lt;code&gt;calendar&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&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%2Ft0ht0e60a6r9u9sbn2ns.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft0ht0e60a6r9u9sbn2ns.png" alt="Adapt, test, and replace under one service contract" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The scheduling feature does not change a line of code across those three stages, and the host program does not restart. &lt;strong&gt;Adapting to a system and replacing it are two stages of the same process.&lt;/strong&gt; There is no separate migration project between them.&lt;/p&gt;

&lt;p&gt;Both approaches can coexist. An MCP client can be an ordinary plugin in rutis. But the environment should not determine the limits of what software can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The foundation: replace one piece while the system keeps running
&lt;/h2&gt;

&lt;p&gt;For software to iterate this way, it first needs to be split into pieces that can be replaced individually at runtime. Those pieces are plugins.&lt;/p&gt;

&lt;p&gt;Plugin systems are not new. But replacing plugins frequently while a system is running demands stronger guarantees. The rutis core focuses on a few of them, each stated as a promise and backed by tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A plugin does not start before its dependencies are ready.&lt;/strong&gt; It declares the services it needs and runs only when all of them are available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything it registers is cleaned up exactly once when it stops.&lt;/strong&gt; Services, listeners, background tasks, and child plugins are released in the reverse order of registration—no more and no less.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A failed startup rolls back.&lt;/strong&gt; Anything already registered is withdrawn, leaving no half-finished state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replacing one piece restarts only the parts that use it.&lt;/strong&gt; When a service provider changes, its dependent plugins stop and wait for the new provider to become ready. Unrelated parts keep running.&lt;/li&gt;
&lt;/ul&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%2Fvznyd8g7uzzy4maflux4.jpg" 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%2Fvznyd8g7uzzy4maflux4.jpg" alt="A connected system capability in its operating environment" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With those guarantees, replacing a component once and replacing it a thousand times should be equally safe. Software can iterate in smaller steps: replace one part instead of releasing the whole system, test it in a real running environment, and switch back if it does not work.&lt;/p&gt;

&lt;p&gt;The term &lt;em&gt;hot update&lt;/em&gt; can mean different things. Some systems replace machine code in place. rutis replaces &lt;strong&gt;running components&lt;/strong&gt;. This approach is in the same tradition as Erlang/OTP and Java's OSGi. Rust's ownership model gives clean unloading a firmer foundation: in a garbage-collected environment, one stray reference can keep an old module alive indefinitely.&lt;/p&gt;

&lt;p&gt;But plugins are only the foundation. What rutis really aims to do is let this kind of iteration &lt;strong&gt;spread outward&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Let iteration cross processes, languages, and devices
&lt;/h2&gt;

&lt;p&gt;If iteration can happen only within one process and one language, the environments software can reach remain limited to that ecosystem. To use Python's model ecosystem, it has to be brought in. To use a device on another machine, someone has to build a separate remote-call layer. Every boundary forces the system to solve startup, dependencies, and cleanup again.&lt;/p&gt;

&lt;p&gt;rutis makes those boundaries invisible to a plugin: &lt;strong&gt;a plugin does not need to know which process provides a service, which language implements it, or which machine runs it&lt;/strong&gt;. It knows the service by name. rutis handles where the service comes from, what happens when the connection drops, and how dependents follow a replacement.&lt;/p&gt;

&lt;p&gt;The following three examples cross three different kinds of boundary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1: an agent whose shell runs on another machine
&lt;/h3&gt;

&lt;p&gt;Imagine an agent built with rutis. Its model calls, conversations, and decisions happen locally, but it needs to execute commands somewhere else—perhaps in an isolated sandbox or on a GPU machine with CUDA installed.&lt;/p&gt;

&lt;p&gt;The shell can be a plugin running in a Python runtime on that machine:&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;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rutis&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;define_plugin&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Shell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_subprocess_shell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;STDOUT&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;communicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Shell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;define_plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Shell&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That machine runs a listening Python runtime with &lt;code&gt;shell_tool&lt;/code&gt; installed. The rutis host where the agent lives decides how to configure the plugin and when it starts and stops:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"rows"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"sandbox"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"rutis-host/dial"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"wss://sandbox.example.com:7443/rutis"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"sandbox:shell_tool"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an architecture example, not a complete deployment recipe. The remote runtime also needs TLS and a shared token; the &lt;a href="https://github.com/arcships/rutis/blob/main/docs/guide/nodes.en.md#a-language-runtime-on-another-machine" rel="noopener noreferrer"&gt;node connection guide&lt;/a&gt; covers those steps.&lt;/p&gt;

&lt;p&gt;The agent's side depends only on the name &lt;code&gt;shell&lt;/code&gt;. As a result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Moving to another execution environment&lt;/strong&gt; requires changing one address in the configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If the remote machine disconnects&lt;/strong&gt;, the parts that depend on &lt;code&gt;shell&lt;/code&gt; stop and wait instead of crashing. They load again when the connection returns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The execution environment can evolve too.&lt;/strong&gt; The shell plugin may begin in Python and later be replaced with a Go version without changing the agent's code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent's "hand" has reached another machine, yet it uses that hand much as it would a local one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 2: a server with components spread across processes and machines
&lt;/h3&gt;

&lt;p&gt;Consider a more familiar case: a backend service.&lt;/p&gt;

&lt;p&gt;Its main logic is written in Rust, but different supporting components belong in different places:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Server's main logic (Rust)
  ├─ Database client                 Same process
  ├─ Third-party API integration     Python process, using the official SDK
  ├─ Inference service               Runtime on a GPU machine
  └─ Adapter for a legacy system     To be replaced with an in-house implementation later
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each component is a plugin that provides a named service. The main logic uses those services by name. Where they run and which language implements them live in configuration, not in the callers' code.&lt;/p&gt;

&lt;p&gt;This has several consequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Failures have boundaries.&lt;/strong&gt; If the Python process crashes, the services it provided are withdrawn and their dependents stop and wait. Other parts of the same host keep running. rutis can also restart a failed runtime according to a backoff policy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A configuration change does not leave the service half-broken.&lt;/strong&gt; Reloading configuration at runtime is all-or-nothing. If the new configuration is invalid, the old one keeps running unchanged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapt first, replace later&lt;/strong&gt; happens here. A plugin initially wraps the legacy system. Once the service contract has settled under real traffic, it is replaced with an in-house implementation. The main logic does not need to know this happened.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example 3: multiple rutis hosts sharing capabilities
&lt;/h3&gt;

&lt;p&gt;The final boundary is the device. Each rutis host can be a node in a network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Office node ── exports calendar ──▶ Cloud node running the agent ◀── exports device ── Home node
            ◀── shared services · remote plugins · forwarded events ──▶
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nodes are joined by an encrypted connection. Over that connection, they can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Share services:&lt;/strong&gt; export a local service to another node or import a remote service as a local one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run plugins on another node:&lt;/strong&gt; a plugin uses that machine's services while its configuration and lifecycle are controlled from here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forward events:&lt;/strong&gt; an event on one side can be received on the other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A dropped connection reconnects automatically. While the other node is offline, the parts that depend on it wait and then resume when it returns.&lt;/p&gt;

&lt;p&gt;This is the clearest picture of iteration spreading outward: &lt;strong&gt;each node contributes the capabilities of its own environment&lt;/strong&gt;. The office node can reach internal systems, the home node can reach devices at home, and the cloud node has compute capacity. When one node learns to connect to a system, software across the network gains access to that capability.&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%2Fkfe73v43er1ki8f47krm.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkfe73v43er1ki8f47krm.png" alt="Office, home, and cloud nodes contribute capabilities across one network" width="800" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further ahead, phone and desktop apps could join in the same way. An app could expose contacts, location, or notifications as plugins, connect to rutis, and become part of the network. This part is still at the design stage, but the direction is the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Give the stable parts to Rust and the changing parts to the ecosystems
&lt;/h2&gt;

&lt;p&gt;This works because rutis makes a basic division:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Give what is stable and unlikely to change to the systems layer. Give what changes and needs an ecosystem to other languages.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The stable part&lt;/strong&gt; is the lifecycle: what starts first, what happens when a dependency disappears, how cleanup works, and what cannot be done across a process boundary. rutis implements those rules once, in Rust. Its core depends on tokio and only a handful of other libraries. Each guarantee is recorded and tied to specific tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The changing part&lt;/strong&gt; is connection and adaptation. Python has an ecosystem for AI and data processing; Node has npm and existing Cordis plugins; Go has a large set of infrastructure libraries; and another machine has its own processes and devices. On these language-specific sides, there is only a small SDK, not another implementation of the framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This division also describes a progression over time. A capability often starts in Python or TypeScript so it can be tried quickly. Real use gradually clarifies its shape. The parts that have stood the test of time can then be rewritten in Rust for reliability and performance. An early design note put it this way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TypeScript is the lab; Rust takes the graduates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which parts deserve to "graduate"? Parts whose meaning has settled; parts that are mechanisms rather than wording; parts that are performance-sensitive or sit on a trust boundary. For an agent, for example, &lt;strong&gt;the mechanism for assembling prompts can be made permanent, while the prompt content should remain changeable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because consumers depend only on service names, the path from experiment to stable implementation can be taken one step at a time. There is no need to stop one day for a large migration. Each additional runtime connects the software's ability to evolve to another ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. A new container for growth
&lt;/h2&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%2Fuwtnxl9pxcg5n0ges89w.jpg" 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%2Fuwtnxl9pxcg5n0ges89w.jpg" alt="A glass vessel holds a growing blue sphere" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Placing rutis next to an operating system helps clarify what it is.&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;Traditional operating system&lt;/th&gt;
&lt;th&gt;rutis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Assumption&lt;/td&gt;
&lt;td&gt;The program has already been written and runs inside it&lt;/td&gt;
&lt;td&gt;The program keeps growing and changing while it runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What it manages&lt;/td&gt;
&lt;td&gt;CPU, memory, and processes&lt;/td&gt;
&lt;td&gt;Connections and capabilities: who provides what, and who depends on whom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boundary&lt;/td&gt;
&lt;td&gt;One machine&lt;/td&gt;
&lt;td&gt;Across processes, languages, and devices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How a program gains a new capability&lt;/td&gt;
&lt;td&gt;Install software or a driver&lt;/td&gt;
&lt;td&gt;Write a plugin to connect to something, try it, and replace it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main concern&lt;/td&gt;
&lt;td&gt;Isolation and scheduling&lt;/td&gt;
&lt;td&gt;Whether the whole system remains correct and clean after one piece is replaced&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;rutis does not replace the operating system; it runs on top of it. An operating system lets programs run. rutis aims to let programs &lt;strong&gt;grow&lt;/strong&gt;. From the perspective of rutis, plugins are like processes, services are like system calls, and language runtimes and remote nodes are like drivers. All of them follow the same lifecycle rules; none receives special treatment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;For the first time, software has a chance to understand and engage with the world around it on its own. Instead of waiting for someone else to prepare an interface, it can go out, connect, try, improve, and, when needed, replace what is there.&lt;/p&gt;

&lt;p&gt;That requires a container that remains reliable through frequent change, one that is not confined to a process, a language, or a device. That is what rutis aims to become.&lt;/p&gt;

&lt;p&gt;The rutis lifecycle model comes from &lt;a href="https://github.com/shigma/cordis" rel="noopener noreferrer"&gt;Cordis&lt;/a&gt; by Shigma. rutis implements it in Rust and carries it across more languages, processes, and machines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it with Node 22+:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @arcships/rutis-host new weather --lang node
&lt;span class="nb"&gt;cd&lt;/span&gt; weather &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm install
npx rutis-host dev        &lt;span class="c"&gt;# Run the plugin and reload it automatically when files change&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python, Bun, and Go can be starting points as well.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/arcships/rutis" rel="noopener noreferrer"&gt;https://github.com/arcships/rutis&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Design philosophy: &lt;a href="https://github.com/arcships/rutis/blob/main/docs/design-philosophy.en.md" rel="noopener noreferrer"&gt;How rutis is designed&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;English translation prepared with AI assistance. Original article by Eric Cheng.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>architecture</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
