By duskzhen
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:
"Keep an eye on my bike for me."
A naive implementation is to have the Agent poll the camera feed every few seconds:
Bike is still there. Bike is still there. Bike is still there. Someone walked past. Bike is still there.
By morning, the bike is safe—and the context window is completely blown.
Sure, that approach works. 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.
While designing Dim, we came back to this scenario so often that we started calling it our "Bike Theft Theory." It illustrates a simple core principle: Just because the environment is constantly changing doesn't mean the model needs to be constantly thinking.
The Camera Records; the Agent Checks on Demand
Let's try a different setup.
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.
Only then does the Agent pull up the relevant video clips: When did this person arrive? Did they just walk past, or are they tampering with the lock? Has the bike moved?
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.
Here, the notification's only job is to say, "Something happened that's worth looking into." Someone approaching is a clue; whether they are stealing the bike requires looking at the evidence.

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.)
What if the detector misses something? The owner might walk out the next morning, see the bike is gone, and ask: "What happened last night?" As long as the underlying records exist, the Agent can work backward from that question and inspect the past.
To pull this off, the system has to solve two distinct problems:
- Leave behind records that might be needed later.
- Pull the Agent's attention over at the right moment.
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.
This exact division of labor is where Dim's Timeline and Event-Driven Architecture begin.
Why Chat History Alone Isn't Enough
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.
With Dim, we wanted to take a step further outside the chat box.
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.
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.
Going back to the bike: "The camera recorded this footage" and "The Agent watched this footage" are fundamentally different facts.
Dim's Timeline 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. The scope of what's recorded on the Timeline is intentionally broader than what the model sees in any single inference request.
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.
The Timeline: Giving Every Event a Deterministic Place
The word "Timeline" might sound like a simple timestamped log. In Dim, however, it defines the canonical execution order of the runtime.
Every branch has its own Timeline. As events are appended, the Timeline assigns a monotonically increasing sequence number. The runtime understands causality and order strictly through this sequence; a wall clock can tell a human when something happened, but it cannot replace the deterministic order of the sequence.
Why does this matter?
Suppose you tell the Agent, "Forget about the bike for now," right as a slow background detector finally returns "Someone is approaching." 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.
In our bike analogy, the Timeline looks like this:
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. New conclusions don't overwrite old facts, either. First we record "Approach Detected," and later we record "Confirmed just passing by." We know both the current state of the world and the exact reasoning trail that got us there.
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 after an event batch is successfully committed to disk, which in turn allows the Dispatcher to broadcast them. Returning from append, committing to storage, and publishing to subscribers are explicitly distinct phases (see Timeline commit and publish implementation).
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.
Event-Driven Runtime: Only Wake Up What Needs to Move
Once you have a Timeline, something needs to consume it.
Dim uses a Dispatcher 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 Dispatcher subscription and dispatch implementation).
Being "event-driven" happens first and foremost between these runtime components. It does not mean firing an LLM request for every single event.
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.
We strictly separate three stages:
| Stage | What It Means |
|---|---|
| Record Event | The fact has entered the auditable history. |
| Dispatch Event | Interested runtime capabilities can react to it. |
| Deliver to Model | Relevant content has entered the model-visible context via inputs or tool results. |
Recording an event does not mean the model knows about it yet.
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 input/consumed occurs does the history projection expand it into an actual model message (see Input consumption and message projection).

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.
This gives us a two-tier filter for "what's worth looking at." 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.
No Bike Required: Background Commands as a Real-World Example
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?
Dim's background execution capability follows the exact path we just described:
- The command finishes, emitting an
exec/endedevent with the execution result. - Once committed and published, the Dispatcher routes the event to the background execution capability.
- The capability checks the exit status and branch state; if wake-up conditions are met, it appends a notification input.
- The notification wraps a
<dim-notification>tag, a short output preview, and instructions on how to fetch the full log, entering the scheduler as aSteerinput. - Once the input is consumed, the model reads the notification in its next turn and decides what to do.
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 Background result handling and Notification input construction).
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.
The model never has to spin in a loop asking, "Is it done yet?" And when the command does 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.
At this point, the Timeline handles recording and ordering, and the event-driven runtime handles reaction and scheduling. That leaves one final puzzle: When the model receives this text in its context, how does it know what the message actually means?
Meta Prompt: Teaching the Model How to Read Its Inputs
In our previous post on Dim's Meta Prompt (An Input Manual for Models), 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 user role.
If the model relies solely on the message role, it can easily confuse "The human user just gave me a new command" with "A background process from five minutes ago just exited."
The bike analogy works the same way. When the camera says "Someone is approaching," that's a sensor observation. When the owner says "Check who was just near my bike," 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.
Dim's Meta Prompt 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:
- For
<dim-notification>(Background Alerts): 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. - For
<dim-state>: It explains state-update semantics, where newer values from the same source supersede earlier ones. - For
<dim-rule>: It defines scoping and activation/deactivation lifecycles.
(See Input Guide implementation and Background notification semantics.)
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.
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 meaning, while the runtime strictly enforces permission checks before any tool action is executed.
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.
Making the Entire Harness Part of the Intelligence
Now, let's wire all these pieces together.
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.

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.
When you view an Agent Harness 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.
This separation also makes long-horizon tasks sustainable:
- Context Compression & Recall: 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
recalltool lets it search and retrieve prior conversations and work records on demand. Compression only changes what is packed into the current inference request—the underlying historical facts remain safely stored on the Timeline (see Context compression checkpoints and Recall tool). - Idempotent Crash Recovery: Recovery respects the boundary between state and side effects. Re-reading a record that says "Alert already sent to owner" 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 Time-bus side-effect guarantees).
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.
What's truly worth engineering is the coordination between the runtime and the model:
- Can past records be retrieved when needed?
- Do notifications provide enough clues without overwhelming the context?
- Does the model understand the provenance and authority of incoming messages?
- Does it have the evidence required to act, and does it get feedback after acting?
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.
That is the exact coordination we're building in Dim—making sure environmental changes are reliably recorded and routed, so the model can see clearly right when it needs to.
The Dim repository contains the Rust implementation discussed here.
Editorial note: AI tools assisted with the English adaptation and visuals.



