Memory Without a Single Transcript: Trees, Branches, and Compaction
Pi's session system answers a deceptively difficult question: how can a coding task remain understandable when the user revisits an old idea, explores alternatives, or runs out of model context? This chapter follows the established coding-agent session from append-only storage through branch navigation and compaction. The goal is practical: predict what remains in the session file, what the model sees on the active path, and what information can be lost when history is summarized.
The answer is not to keep sending an ever-growing transcript. Pi stores a richer local history than any one provider request needs, then constructs the active context from that history. A session is a tree, not just a list, and compaction is a projection boundary, not a deletion command. Once those distinctions are clear, commands such as /tree, /fork, /clone, and /compact stop looking like unrelated interface features.
A session is a tree with a moving leaf
The coding-agent SessionManager stores sessions as JSONL files. Each entry has a stable identifier and a parentId; appending creates a child of the current leaf. The leaf is the current position from which the next entry will grow. Moving the leaf to an earlier entry does not rewrite or delete the entries that came after it. The old path remains available as an alternative branch.
This is a different model from a conventional chat history in which the latest message is simply the end of one linear array. Suppose Pi has helped investigate a failing test and the user decides to try a different repair. With a tree, the user can move back to the earlier request and submit a new answer. The first repair remains in the file as one child path, while the second repair becomes another. The user can compare the alternatives without copying the entire conversation by hand or losing the original reasoning.
The active leaf determines what is relevant to the next turn. To build the session context, Pi walks from that leaf through its parents to the root. It can then project entries into messages the agent understands. Ordinary user, assistant, and tool-result messages participate in context. Model changes and thinking-level changes update the runtime settings. Branch summaries and compaction entries become context-bearing summary messages. A plain custom entry created by an extension is retained as application state but does not enter the model context. A custom message can enter context when an extension deliberately needs to tell the model something.
That separation lets the file serve several audiences. The interactive UI can render the full tree, including labels, tool activity, and abandoned branches. A session manager can recover the current model and thinking level from the active path. The provider receives only the projected message list. An extension can scan its own custom entries to rebuild state. “Stored” and “sent to the model” are therefore different properties of an entry.
Branch commands make the leaf semantics visible. /tree moves within the same session file and keeps alternatives together.