Skip to content

Commit ffc7682

Browse files
committed
feat: add docs/session-persistence.md
1 parent 4b33392 commit ffc7682

2 files changed

Lines changed: 278 additions & 0 deletions

File tree

docs/session-persistence.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# 会话持久化机制
2+
3+
Deep Code 会把每个项目的会话记录保存在本机用户目录中。会话历史用于 `/resume``/continue``/undo`,不依赖当前终端进程是否仍在运行。
4+
5+
## 存储位置
6+
7+
每个项目都有独立的存储目录:
8+
9+
```text
10+
~/.deepcode/projects/<project-code>/
11+
```
12+
13+
`<project-code>` 由项目根目录路径生成。普通路径会转换为安全的目录名;路径过长时,Deep Code 会保留项目名的一部分,并追加稳定哈希,以避免存储路径过长。
14+
15+
项目存储目录包含以下主要文件和目录:
16+
17+
| 路径 | 说明 |
18+
| ---- | ---- |
19+
| `sessions-index.json` | 当前项目的会话索引,保存会话列表和每个会话的概要信息。 |
20+
| `<session-id>.jsonl` | 单个会话的消息记录。每一行是一条 JSON 格式的消息。 |
21+
| `file-history/.git` | 用于代码快照的内部 Git 仓库,供 `/undo` 恢复文件内容。 |
22+
23+
## 持久化内容
24+
25+
### 会话索引
26+
27+
`sessions-index.json` 保存最近的会话条目。每个条目包含:
28+
29+
- 会话 ID、标题、创建时间和更新时间。
30+
- 会话状态,例如 `pending``processing``completed``failed``interrupted``ask_permission``waiting_for_user`
31+
- 最近一次 assistant 回复、思考内容、拒绝原因和失败原因。
32+
- 最近一次工具调用信息、token 用量和活跃 token 数。
33+
- 当前会话中仍被跟踪的子进程信息。
34+
35+
会话标题默认来自首次用户输入的前 100 个字符。使用会话列表中的重命名功能会更新索引里的标题。
36+
37+
### 消息文件
38+
39+
每个会话有一个独立的 JSONL 消息文件,文件名是 `<session-id>.jsonl`。消息按追加顺序写入,常见字段包括:
40+
41+
| 字段 | 说明 |
42+
| ---- | ---- |
43+
| `id` | 消息 ID。 |
44+
| `sessionId` | 所属会话 ID。 |
45+
| `role` | 消息角色:`system``user``assistant``tool`|
46+
| `content` | 文本内容。 |
47+
| `contentParams` | 结构化内容,例如图片输入。 |
48+
| `messageParams` | 模型消息参数,例如 tool call ID、tool calls、reasoning content。 |
49+
| `visible` | 是否在界面中显示。 |
50+
| `compacted` | 是否已经被长会话压缩替代。 |
51+
| `checkpointHash` |`/undo` 关联的代码快照哈希。 |
52+
| `meta` | 工具展示、skill、权限、摘要等附加信息。 |
53+
54+
读取消息文件时,Deep Code 会逐行解析 JSON;无法解析的行会被忽略,以便尽量保留其余可用历史。
55+
56+
### 代码快照
57+
58+
Deep Code 使用 `file-history/.git` 保存代码快照。这个仓库只作为内部文件历史使用,不是项目仓库本身。
59+
60+
- 新会话会初始化一条以会话 ID 命名的内部分支。
61+
- 每次用户输入前,会记录已跟踪文件的状态。
62+
- 工具修改文件前后,会按需记录相关文件的状态。
63+
- 用户消息上的 `checkpointHash` 用来把某次对话位置和对应的代码状态关联起来。
64+
65+
快照只覆盖 Deep Code 已跟踪到的文件;无关文件不会因为 `/undo` 被任意改写。
66+
67+
## 会话生命周期
68+
69+
### 创建会话
70+
71+
创建新会话时,Deep Code 会:
72+
73+
1. 生成新的会话 ID。
74+
2. 初始化该会话的代码快照分支。
75+
3.`sessions-index.json` 中添加会话条目。
76+
4. 写入系统提示、运行时上下文、项目指令和用户消息。
77+
5. 启动模型请求,并在 assistant 回复和工具执行过程中持续更新索引和消息文件。
78+
79+
项目级会话列表最多保留最近 50 条记录。超过上限时,较旧会话会从索引中移除,其消息文件和相关运行时资源也会被清理。
80+
81+
### 继续会话
82+
83+
`/resume` 会显示当前项目的历史会话列表,并选择一个会话继续。
84+
85+
`/continue` 会优先继续当前活动会话;如果没有可继续的活动会话,则进入历史会话选择流程。
86+
87+
继续会话时,Deep Code 会读取会话消息文件,过滤已压缩的旧消息,修复未完成的工具调用上下文,并把可用历史转换为模型请求消息。
88+
89+
### 长会话压缩
90+
91+
当会话上下文过长时,Deep Code 会触发压缩流程:
92+
93+
- 选取较早的一段非系统消息生成摘要。
94+
- 将这段旧消息标记为 `compacted: true`
95+
- 在消息序列中插入一条不可见的系统摘要消息。
96+
97+
后续请求只会使用未压缩消息和摘要消息。原始消息仍保留在 JSONL 文件中,用于审计和界面历史展示。
98+
99+
### 中断、失败和权限等待
100+
101+
会话状态会随运行过程更新:
102+
103+
- 用户中断后,状态会变为 `interrupted`,并清理当前会话控制器和被跟踪的子进程。
104+
- 请求失败时,状态会变为 `failed`,失败原因写入索引。
105+
- 工具调用需要确认时,状态会变为 `ask_permission`
106+
- 工具需要用户输入时,状态会变为 `waiting_for_user`
107+
108+
这些状态都会持久化到 `sessions-index.json`,因此重新打开 CLI 后仍能在会话列表中看到。
109+
110+
## `/undo` 如何使用持久化数据
111+
112+
`/undo` 的候选项来自可见且未压缩的用户消息。每个候选项会检查是否有关联的 `checkpointHash`,并确认对应快照是否可恢复。
113+
114+
根据选择,Deep Code 可以执行以下操作:
115+
116+
| 操作 | 行为 |
117+
| ---- | ---- |
118+
| 恢复对话 | 截断所选用户消息之前的消息历史,并更新索引中的最新 assistant 信息。 |
119+
| 恢复代码 |`file-history/.git` 中读取所选快照,并还原被跟踪文件。 |
120+
| 同时恢复 | 先恢复代码,再截断对话历史。 |
121+
122+
恢复对话会重写该会话的 JSONL 文件;恢复代码会修改工作区中被快照跟踪的文件。
123+
124+
## 删除和重命名
125+
126+
在会话列表中删除会话会:
127+
128+
-`sessions-index.json` 移除该条目。
129+
- 删除对应的 `<session-id>.jsonl` 文件。
130+
- 清理该会话的内存状态、临时工作目录状态、控制器和仍被跟踪的进程控制信息。
131+
132+
重命名会话只更新索引中的 `summary` 字段,不会改动消息文件或代码快照。
133+
134+
## 注意事项
135+
136+
- 会话数据保存在本机用户目录下,并按项目分隔。
137+
- 移动项目目录后,新的项目根路径会生成新的 `<project-code>`;旧路径对应的历史不会自动迁移。
138+
- `file-history/.git` 是 Deep Code 的内部快照仓库,不应手动修改。
139+
- 会话删除不会清理内部 Git 仓库中的所有历史对象;它主要删除会话索引、消息文件和运行时资源。

docs/session-persistence_en.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Session Persistence
2+
3+
Deep Code stores per-project session history in the local user directory. This history powers `/resume`, `/continue`, and `/undo`, and it remains available after the current terminal process exits.
4+
5+
## Storage Location
6+
7+
Each project has its own storage directory:
8+
9+
```text
10+
~/.deepcode/projects/<project-code>/
11+
```
12+
13+
`<project-code>` is generated from the project root path. Normal paths are converted into safe directory names. When the path would be too long, Deep Code keeps part of the project name and appends a stable hash so the storage path stays safe.
14+
15+
The project storage directory contains these main files and directories:
16+
17+
| Path | Description |
18+
| ---- | ----------- |
19+
| `sessions-index.json` | Session index for the current project, including the session list and summary metadata. |
20+
| `<session-id>.jsonl` | Message log for one session. Each line is one JSON message. |
21+
| `file-history/.git` | Internal Git repository used for code checkpoints restored by `/undo`. |
22+
23+
## Persisted Data
24+
25+
### Session Index
26+
27+
`sessions-index.json` stores recent session entries. Each entry includes:
28+
29+
- Session ID, title, creation time, and update time.
30+
- Session status, such as `pending`, `processing`, `completed`, `failed`, `interrupted`, `ask_permission`, or `waiting_for_user`.
31+
- Latest assistant reply, thinking content, refusal reason, and failure reason.
32+
- Latest tool-call data, token usage, and active token count.
33+
- Metadata for subprocesses still tracked by the session.
34+
35+
The default session title comes from the first 100 characters of the first user prompt. Renaming a session from the session list updates the title in the index.
36+
37+
### Message Files
38+
39+
Each session has a separate JSONL message file named `<session-id>.jsonl`. Messages are appended in order. Common fields include:
40+
41+
| Field | Description |
42+
| ----- | ----------- |
43+
| `id` | Message ID. |
44+
| `sessionId` | Owning session ID. |
45+
| `role` | Message role: `system`, `user`, `assistant`, or `tool`. |
46+
| `content` | Text content. |
47+
| `contentParams` | Structured content, such as image input. |
48+
| `messageParams` | Model message parameters, such as tool call IDs, tool calls, and reasoning content. |
49+
| `visible` | Whether the message is shown in the UI. |
50+
| `compacted` | Whether the message has been replaced by long-session compaction. |
51+
| `checkpointHash` | Code checkpoint hash associated with `/undo`. |
52+
| `meta` | Extra metadata for tool display, skills, permissions, summaries, and related features. |
53+
54+
When loading a message file, Deep Code parses JSON one line at a time. Malformed lines are ignored so the remaining usable history can still be loaded.
55+
56+
### Code Checkpoints
57+
58+
Deep Code stores code checkpoints in `file-history/.git`. This repository is only internal file history; it is not the project Git repository.
59+
60+
- A new session initializes an internal branch named after the session ID.
61+
- Before each user prompt, Deep Code records the state of files it already tracks.
62+
- Before and after tool-based file mutations, Deep Code records the relevant file state as needed.
63+
- `checkpointHash` on user messages links a conversation position to a code state.
64+
65+
Checkpoints only cover files Deep Code has tracked. Unrelated files are not arbitrarily rewritten by `/undo`.
66+
67+
## Session Lifecycle
68+
69+
### Creating A Session
70+
71+
When creating a new session, Deep Code:
72+
73+
1. Generates a new session ID.
74+
2. Initializes the code checkpoint branch for that session.
75+
3. Adds an entry to `sessions-index.json`.
76+
4. Writes system prompts, runtime context, project instructions, and the user message.
77+
5. Starts the model request and keeps updating the index and message file as assistant replies and tool executions complete.
78+
79+
The per-project session list keeps the 50 most recent entries. When the limit is exceeded, older sessions are removed from the index, and their message files and related runtime resources are cleaned up.
80+
81+
### Continuing A Session
82+
83+
`/resume` shows the current project's session history and lets you select a session to continue.
84+
85+
`/continue` first continues the active session. If there is no active session to continue, it opens the session selection flow.
86+
87+
When continuing a session, Deep Code reads the message file, filters compacted old messages, repairs incomplete tool-call context, and converts the usable history into model request messages.
88+
89+
### Long-Session Compaction
90+
91+
When the conversation context grows too large, Deep Code can compact earlier messages:
92+
93+
- It summarizes an older range of non-system messages.
94+
- It marks those old messages as `compacted: true`.
95+
- It inserts an invisible system summary message into the message sequence.
96+
97+
Future requests use the remaining active messages and the summary message. The original messages stay in the JSONL file for auditability and UI history.
98+
99+
### Interruptions, Failures, And Permission Waits
100+
101+
Session status changes during execution:
102+
103+
- After a user interruption, status becomes `interrupted`, and Deep Code clears the current session controller and tracked subprocesses.
104+
- After a request failure, status becomes `failed`, and the failure reason is written to the index.
105+
- When a tool call needs confirmation, status becomes `ask_permission`.
106+
- When a tool needs user input, status becomes `waiting_for_user`.
107+
108+
These states are persisted in `sessions-index.json`, so they remain visible in the session list after reopening the CLI.
109+
110+
## How `/undo` Uses Persistent Data
111+
112+
`/undo` candidates come from visible, non-compacted user messages. Each candidate is checked for an associated `checkpointHash`, and Deep Code verifies whether the checkpoint can be restored.
113+
114+
Depending on the selected mode, Deep Code can perform these operations:
115+
116+
| Operation | Behavior |
117+
| --------- | -------- |
118+
| Restore conversation | Truncates message history before the selected user message and updates the latest assistant data in the index. |
119+
| Restore code | Reads the selected checkpoint from `file-history/.git` and restores tracked files. |
120+
| Restore both | Restores code first, then truncates the conversation history. |
121+
122+
Restoring conversation rewrites the session JSONL file. Restoring code modifies workspace files tracked by the selected checkpoint.
123+
124+
## Delete And Rename
125+
126+
Deleting a session from the session list:
127+
128+
- Removes the entry from `sessions-index.json`.
129+
- Deletes the matching `<session-id>.jsonl` file.
130+
- Clears in-memory state, temporary working-directory state, controllers, and tracked process controls for that session.
131+
132+
Renaming a session only updates the `summary` field in the index. It does not change message files or code checkpoints.
133+
134+
## Notes
135+
136+
- Session data is stored in the local user directory and separated by project.
137+
- If a project directory is moved, the new project root path generates a new `<project-code>`; history for the old path is not migrated automatically.
138+
- `file-history/.git` is Deep Code's internal checkpoint repository and should not be edited manually.
139+
- Deleting a session does not remove every historical object from the internal Git repository. It mainly removes the session index entry, message file, and runtime resources.

0 commit comments

Comments
 (0)