| 1 | # User Memory |
| 2 | |
| 3 | The user-memory feature gives the model a small persistent note file |
| 4 | that's injected into the system prompt on every turn. It's the place |
| 5 | to put preferences and conventions that should survive across |
| 6 | sessions — "I prefer pytest over unittest", "this codebase uses |
| 7 | 4-space indentation", "always run `cargo fmt` before committing" — |
| 8 | without having to repeat them in every conversation. |
| 9 | |
| 10 | Memory is **opt-in**. When disabled (the default), nothing is loaded, |
| 11 | nothing is intercepted, and the `remember` tool isn't surfaced to the |
| 12 | model. This keeps zero-overhead behavior for users who haven't asked |
| 13 | for the feature. |
| 14 | |
| 15 | ## Enabling memory |
| 16 | |
| 17 | Either set the env var: |
| 18 | |
| 19 | ```bash |
| 20 | export DEEPSEEK_MEMORY=on |
| 21 | ``` |
| 22 | |
| 23 | Accepted truthy values are `1`, `on`, `true`, `yes`, `y`, and |
| 24 | `enabled`. |
| 25 | |
| 26 | …or add to `~/.deepseek/config.toml`: |
| 27 | |
| 28 | ```toml |
| 29 | [memory] |
| 30 | enabled = true |
| 31 | ``` |
| 32 | |
| 33 | Restart the TUI after toggling. Disabling is the same in reverse. |
| 34 | |
| 35 | The memory file lives at `~/.deepseek/memory.md` by default; override |
| 36 | with `memory_path` in `config.toml` or `DEEPSEEK_MEMORY_PATH` in |
| 37 | the environment. `DEEPSEEK_MEMORY_PATH` wins over the config file when |
| 38 | both are set. |
| 39 | |
| 40 | ## Quick examples |
| 41 | |
| 42 | ```text |
| 43 | # remember that this repo prefers cargo fmt before commits |
| 44 | /memory |
| 45 | /memory path |
| 46 | /memory edit |
| 47 | /memory help |
| 48 | ``` |
| 49 | |
| 50 | - Type `# remember that this repo prefers cargo fmt before commits` in |
| 51 | the composer to append a timestamped bullet without firing a turn. |
| 52 | - Run `/memory` to confirm where the feature is writing and what is |
| 53 | currently stored. |
| 54 | - Run `/memory edit` when you want to groom the file manually in your |
| 55 | editor. |
| 56 | |
| 57 | ## What gets injected |
| 58 | |
| 59 | When memory is enabled and the file exists, every turn's system |
| 60 | prompt carries an extra block: |
| 61 | |
| 62 | ```xml |
| 63 | <user_memory source="/Users/you/.deepseek/memory.md"> |
| 64 | - (2026-05-03 22:14 UTC) prefer pytest over unittest |
| 65 | - (2026-05-03 22:31 UTC) this codebase uses 4-space indentation |
| 66 | … |
| 67 | </user_memory> |
| 68 | ``` |
| 69 | |
| 70 | The block sits above the volatile-content boundary in the prompt |
| 71 | assembly so it stays inside DeepSeek's prefix cache turn-over-turn. |
| 72 | The file is read at every prompt-build call — edits via `/memory` |
| 73 | or external editors land on the next turn, no restart needed. |
| 74 | |
| 75 | Files larger than 100 KiB are loaded but truncated, with a marker |
| 76 | appended so you can see the cut. |
| 77 | |
| 78 | ## Three ways to add to memory |
| 79 | |
| 80 | ### 1. The `# ` composer prefix (#492) |
| 81 | |
| 82 | Type a single line that starts with `#` (but not `##` or `#!`) in |
| 83 | the composer: |
| 84 | |
| 85 | ``` |
| 86 | # remember to use 4-space indentation in this repo |
| 87 | ``` |
| 88 | |
| 89 | The TUI intercepts the input and appends a timestamped bullet to |
| 90 | your memory file. **No turn fires** — your input is consumed, the |
| 91 | status line confirms the path it wrote to, and you can keep typing |
| 92 | your real question. |
| 93 | |
| 94 | Multi-`#` prefixes deliberately fall through to normal turn |
| 95 | submission so you can paste Markdown headings without surprise. |
| 96 | |
| 97 | ### 2. The `/memory` slash command (#491) |
| 98 | |
| 99 | Inspect, clear, or get hints about editing the file: |
| 100 | |
| 101 | | Subcommand | Effect | |
| 102 | |---------------------|--------------------------------------------------------| |
| 103 | | `/memory` | Show the resolved path and current contents inline | |
| 104 | | `/memory show` | Alias for the no-arg form | |
| 105 | | `/memory path` | Print just the resolved path | |
| 106 | | `/memory clear` | Replace the file with an empty marker | |
| 107 | | `/memory edit` | Print the `${VISUAL:-${EDITOR:-vi}} <path>` shell line | |
| 108 | | `/memory help` | Show command-specific help and the current path | |
| 109 | |
| 110 | The `/memory edit` form intentionally just prints the command rather |
| 111 | than spawning the editor in-process — that keeps the slash-command |
| 112 | handler simple and consistent regardless of which editor you use. |
| 113 | |
| 114 | You can also discover the feature from the general help surfaces: |
| 115 | |
| 116 | - `/help memory` shows the slash-command summary and usage line. |
| 117 | - `/memory help` prints the memory-specific subcommands plus the |
| 118 | resolved path. |
| 119 | |
| 120 | ### 3. The `remember` tool (auto-update, #489) |
| 121 | |
| 122 | When memory is enabled the model gets a `remember` tool with this |
| 123 | shape: |
| 124 | |
| 125 | ```json |
| 126 | { |
| 127 | "name": "remember", |
| 128 | "description": "Append a durable note to the user memory file...", |
| 129 | "input_schema": { |
| 130 | "type": "object", |
| 131 | "properties": { |
| 132 | "note": { "type": "string", ... } |
| 133 | }, |
| 134 | "required": ["note"] |
| 135 | } |
| 136 | } |
| 137 | ``` |
| 138 | |
| 139 | The model uses this when it notices a durable preference, convention, |
| 140 | or fact worth keeping across sessions. The tool is auto-approved |
| 141 | because writes are scoped to the user's own memory file — gating |
| 142 | them behind the standard write-approval flow would defeat the point |
| 143 | of automatic memory capture. |
| 144 | |
| 145 | If the model uses `remember` for transient task state ("I'm |
| 146 | currently editing foo.rs") the result is harmless but wastes |
| 147 | context. The tool's description explicitly tells the model **not** |
| 148 | to do that — durable, single-sentence notes only. |
| 149 | |
| 150 | ## File format |
| 151 | |
| 152 | Memory is plain Markdown with timestamped bullets: |
| 153 | |
| 154 | ```markdown |
| 155 | - (2026-05-03 22:14 UTC) prefer pytest over unittest |
| 156 | - (2026-05-03 22:31 UTC) this codebase uses 4-space indentation |
| 157 | - (2026-05-04 09:02 UTC) all PRs need 2 reviewers before merge |
| 158 | ``` |
| 159 | |
| 160 | You can hand-edit the file in any editor — the loader doesn't care |
| 161 | about the timestamp format; it just reads the whole file as the |
| 162 | memory block. The timestamp is convention so you can tell when each |
| 163 | note was added when grooming the file. |
| 164 | |
| 165 | ## Hierarchy and imports |
| 166 | |
| 167 | Memory is intentionally **user-scoped** rather than repo-scoped. It |
| 168 | sits alongside — not inside — project instruction sources such as |
| 169 | `AGENTS.md`, `.deepseek/instructions.md`, and `instructions = [...]`. |
| 170 | |
| 171 | - Use **memory** for durable personal preferences that should follow |
| 172 | you across repos and sessions. |
| 173 | - Use **project instructions** for repo-specific conventions that |
| 174 | should travel with the codebase. |
| 175 | |
| 176 | The memory loader currently reads one resolved file path verbatim. |
| 177 | `@path` imports / includes are **not** supported today; if you need a |
| 178 | larger reusable instruction bundle, put it in a project instruction |
| 179 | file or a skill instead. |
| 180 | |
| 181 | ## What stays out of memory |
| 182 | |
| 183 | Memory is for **durable** signal. Things that should NOT live there: |
| 184 | |
| 185 | - **Secrets** — no API keys, tokens, passwords. The file is plain |
| 186 | text on disk and gets injected verbatim into the system prompt. |
| 187 | - **Transient task state** — "I'm currently working on the parser" |
| 188 | changes every session; it doesn't belong in cross-session memory. |
| 189 | - **Conversation snippets** — quote-style notes belong in the notes |
| 190 | tool (`note`), not memory. |
| 191 | - **Long instructions** — anything over a few sentences should live |
| 192 | in `AGENTS.md` (project-level) or in a [skill](../crates/tui/src/skills.rs) |
| 193 | (reusable instruction packs). |
| 194 | |
| 195 | ## Privacy and scope |
| 196 | |
| 197 | The memory file lives entirely on your machine in `~/.deepseek/`. |
| 198 | It's never uploaded to any cloud service — the TUI only ever |
| 199 | includes it inline in the system prompt that the LLM provider |
| 200 | receives, and only when memory is enabled. If you switch providers |
| 201 | (DeepSeek / NVIDIA NIM / Fireworks / etc.) the same memory file is |
| 202 | used; the file is provider-agnostic. |
| 203 | |
| 204 | The file is per-user, not per-project. If you want project-specific |
| 205 | memory, use the project-level `AGENTS.md` or |
| 206 | `.deepseek/instructions.md` files instead — those are loaded by |
| 207 | `project_context` and live in the repo (or wherever you commit |
| 208 | them). |
| 209 | |
| 210 | ## Configuration reference |
| 211 | |
| 212 | ```toml |
| 213 | # ~/.deepseek/config.toml |
| 214 | [memory] |
| 215 | enabled = true # default false; or set DEEPSEEK_MEMORY=on |
| 216 | # Path is configured at the top-level (next to skills_dir, notes_path): |
| 217 | memory_path = "~/.deepseek/memory.md" |
| 218 | ``` |
| 219 | |
| 220 | | Setting | Default | Override | |
| 221 | |-----------------------|-------------------------------|---------------------------------------| |
| 222 | | Memory enabled | `false` | `[memory] enabled = true` or `DEEPSEEK_MEMORY=on` | |
| 223 | | Memory file path | `~/.deepseek/memory.md` | `memory_path = "..."` or `DEEPSEEK_MEMORY_PATH=` | |
| 224 | | Max file size | 100 KiB | (none today; truncation marker shows the cut) | |
| 225 | |
| 226 | ## Related |
| 227 | |
| 228 | - `docs/SUBAGENTS.md` — sub-agents inherit memory and can use the |
| 229 | `remember` tool too. |
| 230 | - `docs/CONFIGURATION.md` — full config reference. |
| 231 | - Issue [#489](https://github.com/Hmbown/DeepSeek-TUI/issues/489) |
| 232 | — phase-1 EPIC tracking the work. |
| 233 |