← Writing

OpenClaw

After a Restart, Does OpenClaw Remember Where It Left Off?

The checklist was saved, then the service restarted. Does remembering the conversation mean knowing the action completed? Follow session indexes, JSONL branches, and missing tool results to find the boundary.

Let's continue the hypothetical scene from the previous articles. OpenClaw has read the meeting notes and extracted three action items. You give it the appropriate file permissions, and this time the checklist is successfully saved to notes/todo.md.

You stop the service, start it again a little later, and ask:

Could you break the second action item down a little further?

If it picks up the conversation, it is tempting to conclude: “Good, it has memory.”

Move the restart slightly earlier, though, and a different question appears. Suppose the file was written, but the process exited before the tool result made it into the session. After restarting, should the assistant elaborate on the second item, save the file again, or first establish what actually happened?

Remembering a conversation and knowing whether an action completed look similar in a chat window. In software, they require different evidence. This article follows that restart to see what OpenClaw preserves and what a conversation transcript cannot establish on its own.

We continue with OpenClaw v2026.5.22 and its embedded execution path using Pi 0.75.4. The discussion concerns session storage in this specific source snapshot, not every version or harness. Session transcripts are also distinct from a separate long-term memory retrieval system. Session storage reference

Find the conversation before opening the notebook

After a restart, OpenClaw first needs to establish which conversation your new message belongs to.

The first article explored sessionKey, which expresses message ownership. Storage adds another question: which sessionId does that key currently identify, and which transcript should be opened? In the default directory, sessions.json holds session entries, while files normally named <sessionId>.jsonl hold transcripts. An entry can also specify its sessionFile path. Session entry definition

Think of the first as a catalog card and the second as a working notebook. The card helps locate the notebook and carries information such as model configuration, update times, and lifecycle metadata. The conversation itself, assistant tool calls, and tool results belong in the notebook.

Even the timestamps on the card answer different questions. This version distinguishes sessionStartedAt, lastInteractionAt, and updatedAt: when the session began, when the last qualifying interaction occurred, and when its stored entry changed. Background bookkeeping should not make an old conversation look freshly active simply because a timestamp was updated. Lifecycle documentation

Consequently, losing conversational continuity after a restart does not necessarily mean the transcript disappeared. Routing may have selected another key, or lifecycle rules may have moved the conversation to a new session. First establish which notebook the system opened; then investigate missing pages.

Session index, JSONL transcript, and live process state have different responsibilities; a stored status cannot revive an executing process
The index locates the transcript, and the transcript helps rebuild context. Work in flight still needs a recovery decision.

There is an important qualification here. Session entries can persist execution-related information, including certain subtask statuses, end times, and whether the previous run was aborted. It would be inaccurate to say that all execution information exists only in memory. But a stored running field is not a living process. Reading that word cannot recreate a network connection, execution stack, or pending control handle.

The notebook has branches

A JSONL file contains one JSON value per line. At first glance, the design looks like a simple chat log: append messages, then read them from beginning to end after restarting.

Pi's SessionManager adds relationships. Each ordinary entry has an id and a parentId, and the manager maintains a current leafId. A newly appended entry becomes a child of the current leaf. To reconstruct context, the manager walks back from that leaf through its parents. SessionManager implementation

Consider a simplified checklist conversation. A is the request to prepare a checklist; B is the first response. You then want a different breakdown and generate another response, C, from A. The file can retain A, B, and C, while the current conversation follows A → C.

Concatenating every message in file order would risk presenting two alternative responses as consecutive events. Parent links let the system express two things separately: what has been recorded, and which path the present conversation follows.

User message A branches into earlier reply B and replacement reply C; the file retains all three, while context follows A to the current leaf C
C has already been appended in this example. B still exists, but it is outside the current context path.

The model has a subtle boundary. Calling branch() only moves the in-memory leaf pointer; it does not immediately persist a record saying “continue from here.” In the local experiment, I moved back to A, appended nothing, and reopened the file. The manager still selected B, the last saved entry. Once C had actually been appended, reopening reconstructed the new path through C's parent link.

“Supports branches” therefore does not mean that every navigation action is durably saved. You must examine what the surrounding application writes after changing branches. This experiment concerns the underlying Pi manager; it does not establish that a particular OpenClaw interface loses a user's selection. Branching and loading logic

Recorded content need not all reach the model

As the discussion of the meeting grows, the next request cannot carry an unlimited amount of original text.

buildSessionContext() does more than export a file. It identifies the current branch and processes any compaction entry on that path. With compaction, it emits a summary, retains the relevant messages from the designated retention point, and includes messages added after compaction. Older entries may remain in the file even though the model's context is organized differently. Context construction

There is another distinction. An extension can append a custom entry to preserve its own data without automatically adding it to model context. Extensions that need conversational content have a separate custom_message path. A file can serve several purposes; “stored” does not mean “the model definitely received it.”

This is why searching raw JSONL alone cannot explain every omission. Finding a sentence proves it was recorded. You still need to establish whether it belongs to the current branch and whether it survived compaction and subsequent history processing into this model request. We stop at session context construction here; a later article will examine compaction policy in more detail.

If text appeared in chat, was it saved?

Return to the moment just before the restart.

When Pi's AgentSession receives an event, it notifies extensions and listeners before handling session persistence for message_end. Ordinary user messages, assistant messages, and tool results then pass to sessionManager.appendMessage(). Observing an event alone therefore does not prove the disk record has been written. Event and persistence ordering

The manager has another detail worth noticing. In a new session without an assistant message, Pi initially keeps entries in memory. When the first assistant message arrives, it writes the accumulated header, user message, and assistant message. Subsequent entries normally append to the file. Using a real temporary directory, I verified that a first user message alone did not create the file, and that the conversation could be reopened after the assistant message arrived.

That local result should not be turned into “OpenClaw always waits for a reply before saving user messages.” The surrounding application also has pre-created files, write guards, and explicit flush paths. OpenClaw's prepareSessionManagerForRun() handles a particular starting condition: a file already exists but has no assistant message. It normalizes the manager and file state so that the first subsequent flush has the correct ordering. OpenClaw initialization adapter

This illustrates why embedding an agent library involves more than calling prompt(). Both the surrounding system and the library may touch the same session file. Their interpretations of “the file exists” and “the session has been flushed” need to agree at that boundary.

There is a further distinction between a successful synchronous file write and guaranteed survival after a power failure. This investigation did not test power loss, forcibly killed processes, or disk faults, and it makes no durability guarantee for those conditions. The checks concern writing and reopening files under normal filesystem operations.

The hardest gap is a tool result that never returned

Suppose saving the checklist proceeds as follows: the model requests write, the tool writes the file, and the process exits before a complete result message is retained.

This is a hypothetical failure window used to analyze the boundary, not an OpenClaw failure reproduced in this investigation. The difficulty is that the external world may have changed while the transcript lacks confirmation.

Model APIs also commonly require tool calls and results to be properly paired. A history containing a call without its result can cause a subsequent request to be rejected. OpenClaw therefore has tool-result guards and repair logic around persistence and history preparation. The guard tracks pending calls. Where synthetic results are permitted, it can insert a missing-result entry explicitly marked isError: true. Whether to synthesize one and what it says depend on the applicable policy; this is not an unconditional action on every model path. Persistence guard, Missing-result constructor

But the repair entry means “the result is missing from history,” not “the target file definitely was not written.” It does not travel back to the tool host and undo an earlier write. Nor does it establish that blindly repeating the action is safe.

Conversely, a synthetic result is not a successful receipt from the actual tool. Its purpose is to represent the gap for subsequent processing, not turn an unknown outcome into a known one.

The community has encountered problems with repair timing before. The merged PR #13746 changed the ordering between waiting for agent idle and flushing pending results. It illustrates how declaring a result missing too early can conflict with ongoing work. This is a historical fix, not an old issue being presented as a new bug to claim.

The same boundary matters when an assistant publishes articles, opens tickets, or triggers robot actions. My design would give actions with side effects stable business identifiers and provide result lookup or idempotent requests in the target system. Recovery would check the existing outcome before deciding to retry. That is an engineering recommendation derived from the example, not a claim that OpenClaw's JSONL storage already provides these guarantees for every tool.

Before saying “continue”

This investigation ran 29 local checks using the original Pi session manager and message constructors, OpenClaw's initialization adapter, and an unchanged extraction of its missing-result constructor. Real temporary files exercised writing, reopening, branching, compaction, and error marking. There were no real model calls, no complete OpenClaw runtime, and no end-to-end verification of multiprocess contention or fault recovery.

If I were implementing a small assistant from scratch, I would separate three responsibilities: an index to find a session, structured records to reconstruct context, and independent action-outcome checks to decide whether a retry is appropriate. Index updates can have their own exclusive-write and atomic-write mechanisms; OpenClaw organizes the corresponding storage entry points that way. This still does not turn the index, transcript, and external tool side effects into a single transaction. Index update entry point

Return to “Could you break the second item down further?” Once the system has opened the same conversation and its current context contains the relevant checklist, the assistant has the information needed to continue discussing it. Establishing whether the earlier save completed still depends on the actual tool outcome and, when necessary, inspecting the file itself.

Session persistence lets the conversation continue. Reliable execution also requires recognizing and handling actions whose outcomes remain unconfirmed. Next, we will leave restarts aside and consider another interruption: while you say “keep refining it,” another message says “don't change it yet.” How should two requests in the same session be queued?

继续阅读