mercury-agent 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +452 -451
  2. package/container/Dockerfile +127 -127
  3. package/container/Dockerfile.base +109 -109
  4. package/container/Dockerfile.power +17 -17
  5. package/container/agent-package.json +8 -8
  6. package/container/build.sh +54 -54
  7. package/docs/ROADMAP.md +3 -4
  8. package/docs/archive/summarization/2026-07-02-recent-dev-summary.md +71 -0
  9. package/docs/auth/dashboard.md +28 -28
  10. package/docs/auth/overview.md +109 -109
  11. package/docs/auth/whatsapp.md +173 -173
  12. package/docs/authoring-profiles.md +174 -174
  13. package/docs/configuration.md +54 -54
  14. package/docs/container-lifecycle.md +349 -349
  15. package/docs/{bugs/bwrap-privileged-linux-docker.md → debug/major/2026-07-02-bwrap-privileged-linux-docker.md} +21 -1
  16. package/docs/{bugs/e2big-prompt-delivery-fix.md → debug/major/2026-07-02-e2big-prompt-delivery-fix.md} +27 -1
  17. package/docs/{bugs/registry-pull-no-local-fallback.md → debug/major/2026-07-02-registry-pull-no-local-fallback.md} +27 -1
  18. package/docs/debug/summarization/2026-07-02-common-bug-patterns.md +72 -0
  19. package/docs/deployment.md +199 -199
  20. package/docs/extensions.md +375 -375
  21. package/docs/graceful-shutdown.md +62 -62
  22. package/docs/kb-distillation.md +77 -77
  23. package/docs/media/overview.md +140 -140
  24. package/docs/media/whatsapp.md +171 -171
  25. package/docs/memory.md +137 -137
  26. package/docs/permissions.md +217 -217
  27. package/docs/pipeline.md +228 -228
  28. package/docs/prd-chat-memory.md +76 -76
  29. package/docs/prd-config-load.md +82 -82
  30. package/docs/rate-limiting.md +229 -229
  31. package/docs/runbooks/publish-checklist.md +9 -1
  32. package/docs/scheduler.md +288 -288
  33. package/docs/setup-discord.md +100 -100
  34. package/docs/setup-slack.md +119 -119
  35. package/docs/setup-whatsapp.md +94 -94
  36. package/docs/subagents.md +166 -166
  37. package/docs/web-search.md +62 -62
  38. package/examples/extensions/README.md +12 -12
  39. package/examples/extensions/charts/index.ts +13 -13
  40. package/examples/extensions/charts/skill/SKILL.md +98 -98
  41. package/examples/extensions/gws/README.md +52 -52
  42. package/examples/extensions/gws/skill/SKILL.md +57 -57
  43. package/examples/extensions/gws/skill/references/calendar.md +101 -101
  44. package/examples/extensions/gws/skill/references/docs.md +65 -65
  45. package/examples/extensions/gws/skill/references/drive.md +79 -79
  46. package/examples/extensions/gws/skill/references/gmail.md +85 -85
  47. package/examples/extensions/gws/skill/references/sheets.md +60 -60
  48. package/examples/extensions/napkin/skill/SKILL.md +728 -728
  49. package/examples/extensions/pdf/skill/LICENSE.txt +30 -30
  50. package/examples/extensions/pdf/skill/SKILL.md +314 -314
  51. package/examples/extensions/pdf/skill/forms.md +294 -294
  52. package/examples/extensions/pdf/skill/reference.md +611 -611
  53. package/examples/extensions/pdf/skill/scripts/check_bounding_boxes.py +65 -65
  54. package/examples/extensions/pdf/skill/scripts/check_fillable_fields.py +11 -11
  55. package/examples/extensions/pdf/skill/scripts/convert_pdf_to_images.py +33 -33
  56. package/examples/extensions/pdf/skill/scripts/create_validation_image.py +37 -37
  57. package/examples/extensions/pdf/skill/scripts/extract_form_field_info.py +122 -122
  58. package/examples/extensions/pdf/skill/scripts/extract_form_structure.py +115 -115
  59. package/examples/extensions/pdf/skill/scripts/fill_fillable_fields.py +98 -98
  60. package/examples/extensions/pdf/skill/scripts/fill_pdf_form_with_annotations.py +107 -107
  61. package/examples/extensions/permission-guard/index.ts +65 -65
  62. package/examples/extensions/pinchtab/skill/SKILL.md +224 -224
  63. package/examples/extensions/pinchtab/skill/TRUST.md +69 -69
  64. package/examples/extensions/pinchtab/skill/references/api.md +297 -297
  65. package/examples/extensions/pinchtab/skill/references/env.md +45 -45
  66. package/examples/extensions/pinchtab/skill/references/profiles.md +107 -107
  67. package/examples/extensions/tradestation/host/refresh.ts +102 -102
  68. package/examples/extensions/tradestation/index.ts +153 -153
  69. package/examples/extensions/tradestation/skill/SKILL.md +67 -67
  70. package/examples/extensions/voice-synth/index.ts +94 -94
  71. package/examples/extensions/voice-synth/skill/SKILL.md +38 -38
  72. package/examples/extensions/voice-transcribe/requirements.txt +8 -8
  73. package/examples/extensions/voice-transcribe/scripts/transcribe.py +179 -179
  74. package/examples/extensions/voice-transcribe/skill/SKILL.md +53 -53
  75. package/examples/extensions/yahoo-mail/cli/package.json +13 -13
  76. package/examples/extensions/yahoo-mail/skill/SKILL.md +78 -78
  77. package/package.json +106 -106
  78. package/resources/agents/explore.md +50 -50
  79. package/resources/agents/worker.md +24 -24
  80. package/resources/connection-env-vars.json +25 -25
  81. package/resources/pi-extensions/subagent/agents.ts +126 -126
  82. package/resources/pi-extensions/subagent/index.ts +964 -964
  83. package/resources/profiles/coding/AGENTS.md +43 -43
  84. package/resources/profiles/coding/mercury-profile.yaml +15 -15
  85. package/resources/profiles/general/AGENTS.md +31 -31
  86. package/resources/profiles/general/mercury-profile.yaml +15 -15
  87. package/resources/profiles/research/AGENTS.md +40 -40
  88. package/resources/profiles/research/mercury-profile.yaml +15 -15
  89. package/resources/skills/config/SKILL.md +25 -25
  90. package/resources/skills/context/SKILL.md +33 -33
  91. package/resources/skills/conversation-recap/SKILL.md +19 -19
  92. package/resources/skills/mutes/SKILL.md +31 -31
  93. package/resources/skills/permissions/SKILL.md +19 -19
  94. package/resources/skills/preferences/SKILL.md +31 -31
  95. package/resources/skills/recall/SKILL.md +24 -24
  96. package/resources/skills/roles/SKILL.md +18 -18
  97. package/resources/skills/spaces/SKILL.md +18 -18
  98. package/resources/skills/tasks/SKILL.md +45 -45
  99. package/resources/templates/AGENTS.md +157 -157
  100. package/resources/templates/env.template +38 -38
  101. package/resources/templates/mercury.example.yaml +99 -99
  102. package/src/agent/container-entry.ts +1 -1
  103. package/src/agent/container-runner.ts +1345 -1346
  104. package/src/cli/mercury.ts +39 -7
  105. package/src/cli/mrctl.ts +636 -636
  106. package/src/config-file.ts +540 -540
  107. package/src/config.ts +339 -339
  108. package/src/core/api.ts +125 -125
  109. package/src/core/caller-token.ts +101 -101
  110. package/src/core/permissions.ts +228 -228
  111. package/src/core/profiles.ts +271 -271
  112. package/src/core/routes/capability.ts +70 -70
  113. package/src/core/routes/index.ts +15 -15
  114. package/src/core/runtime.ts +1530 -1530
  115. package/src/dashboard/index.html +729 -729
  116. package/src/extensions/api.ts +273 -273
  117. package/src/extensions/loader.ts +286 -286
  118. package/src/extensions/types.ts +517 -517
  119. package/src/main.ts +605 -605
  120. package/docs/pending-updates/applicative-profiles.md +0 -15
  121. package/docs/pending-updates/caller-bound-capability-token.md +0 -15
  122. package/docs/pending-updates/dm-auto-space.md +0 -15
  123. /package/docs/archive/{2026-07-01-applicative-profiles.md → applicative-profiles/2026-07-01-applicative-profiles.md} +0 -0
  124. /package/docs/archive/{2026-07-01-caller-bound-capability-token.md → applicative-profiles/2026-07-01-caller-bound-capability-token.md} +0 -0
  125. /package/docs/archive/{2026-07-01-dm-auto-space.md → applicative-profiles/2026-07-01-dm-auto-space.md} +0 -0
@@ -1,171 +1,171 @@
1
- # WhatsApp Media Handling
2
-
3
- Downloads media from WhatsApp messages using the Baileys library.
4
-
5
- ## Supported Media Types
6
-
7
- | WhatsApp Type | Detected As | Default MIME | Extensions |
8
- |---------------|-------------|--------------|------------|
9
- | `imageMessage` | `image` | `image/jpeg` | jpg, png, gif, webp |
10
- | `videoMessage` | `video` | `video/mp4` | mp4, 3gp |
11
- | `audioMessage` (ptt=true) | `voice` | `audio/ogg` | ogg |
12
- | `audioMessage` (ptt=false) | `audio` | `audio/mpeg` | mp3, m4a, aac, ogg |
13
- | `documentMessage` | `document` | `application/octet-stream` | pdf, doc, docx, xls, xlsx, txt, etc. |
14
- | `stickerMessage` | `image` | `image/webp` | webp |
15
-
16
- ## Data Flow
17
-
18
- ```
19
- WAMessage (Baileys)
20
-
21
-
22
- detectWhatsAppMedia(msg.message)
23
-
24
- ├─▶ null (no media)
25
-
26
-
27
- WhatsAppMediaInfo { type, mimeType, fileLength?, filename? }
28
-
29
-
30
- downloadWhatsAppMedia(msg, sock, options)
31
-
32
- ├─▶ null (too large / download failed)
33
-
34
-
35
- MessageAttachment { path, type, mimeType, sizeBytes?, filename? }
36
-
37
-
38
- Saved to: {workspace}/inbox/{timestamp}-{type}.{ext}
39
- ```
40
-
41
- ## Implementation
42
-
43
- ### Detection
44
-
45
- ```typescript
46
- // src/adapters/whatsapp-media.ts
47
- function detectWhatsAppMedia(message: proto.IMessage): WhatsAppMediaInfo | null
48
- ```
49
-
50
- Checks message for media fields in order:
51
- 1. `audioMessage?.ptt` → voice note
52
- 2. `audioMessage` → audio
53
- 3. `imageMessage` → image
54
- 4. `videoMessage` → video
55
- 5. `documentMessage` → document
56
- 6. `stickerMessage` → image
57
-
58
- ### Download
59
-
60
- ```typescript
61
- // src/adapters/whatsapp-media.ts
62
- async function downloadWhatsAppMedia(
63
- msg: WAMessage,
64
- sock: WASocket,
65
- options: MediaDownloadOptions,
66
- ): Promise<MessageAttachment | null>
67
- ```
68
-
69
- Uses Baileys' `downloadMediaMessage()`:
70
-
71
- ```typescript
72
- const buffer = await downloadMediaMessage(
73
- msg,
74
- "buffer",
75
- {},
76
- {
77
- logger: silentLogger,
78
- reuploadRequest: sock.updateMediaMessage,
79
- },
80
- );
81
- ```
82
-
83
- ### Adapter Integration
84
-
85
- ```typescript
86
- // src/adapters/whatsapp.ts
87
- createWhatsAppBaileysAdapter({
88
- mediaEnabled: true,
89
- mediaMaxSizeBytes: 10 * 1024 * 1024,
90
- getWorkspace: (spaceId) => ensureSpaceWorkspace(spacesDir, spaceId),
91
- });
92
- ```
93
-
94
- ## Size Limits
95
-
96
- Files are checked against `mediaMaxSizeBytes` twice:
97
-
98
- 1. **Before download** — using `fileLength` from message metadata (may be missing)
99
- 2. **After download** — using actual buffer size
100
-
101
- Files exceeding the limit are logged and skipped:
102
-
103
- ```
104
- [WARN] Skipping large media file messageId=ABC type=video sizeBytes=52428800 maxBytes=10485760
105
- ```
106
-
107
- ## Reply Context
108
-
109
- When replying to a message with media, the reply context includes media info:
110
-
111
- ```typescript
112
- // Attributes added to <reply_to>
113
- media_type="image"
114
- media_mime="image/jpeg"
115
- ```
116
-
117
- Example:
118
- ```xml
119
- <reply_to name="John" jid="123@wa" message_id="ABC" media_type="image" media_mime="image/jpeg">
120
- [image]
121
- </reply_to>
122
- ```
123
-
124
- ## File Naming
125
-
126
- Pattern: `{timestamp}-{type}.{ext}` or `{timestamp}-{filename}` for documents
127
-
128
- | Input | Output |
129
- |-------|--------|
130
- | image/jpeg | `1709012345-image.jpg` |
131
- | audio/ogg (voice) | `1709012345-voice.ogg` |
132
- | application/pdf, "report.pdf" | `1709012345-report.pdf` |
133
-
134
- ## MIME to Extension Mapping
135
-
136
- ```typescript
137
- const MIME_TO_EXT: Record<string, string> = {
138
- "image/jpeg": "jpg",
139
- "image/png": "png",
140
- "image/gif": "gif",
141
- "image/webp": "webp",
142
- "audio/ogg": "ogg",
143
- "audio/mpeg": "mp3",
144
- "audio/mp4": "m4a",
145
- "video/mp4": "mp4",
146
- "video/3gpp": "3gp",
147
- "application/pdf": "pdf",
148
- // ... etc
149
- };
150
- ```
151
-
152
- Unknown MIME types default to `.bin`.
153
-
154
- ## Limitations
155
-
156
- 1. **No re-download** — Media is downloaded once when the message arrives. If the file is deleted, it's gone.
157
-
158
- 2. **No transcription** — Voice notes are saved as audio files. pi cannot play them. Future: add Whisper transcription.
159
-
160
- 3. **Reply context doesn't include file** — When replying to a media message, we include metadata but not the actual file path. The original attachment would need to be looked up.
161
-
162
- 4. **Ephemeral media** — WhatsApp media URLs expire. Download must happen immediately when the message arrives.
163
-
164
- ## Error Handling
165
-
166
- | Error | Behavior |
167
- |-------|----------|
168
- | Download fails | Log error, continue without attachment |
169
- | Buffer empty | Log error, return null |
170
- | Size exceeded | Log warning, discard buffer |
171
- | Write fails | Throw error (propagates up) |
1
+ # WhatsApp Media Handling
2
+
3
+ Downloads media from WhatsApp messages using the Baileys library.
4
+
5
+ ## Supported Media Types
6
+
7
+ | WhatsApp Type | Detected As | Default MIME | Extensions |
8
+ |---------------|-------------|--------------|------------|
9
+ | `imageMessage` | `image` | `image/jpeg` | jpg, png, gif, webp |
10
+ | `videoMessage` | `video` | `video/mp4` | mp4, 3gp |
11
+ | `audioMessage` (ptt=true) | `voice` | `audio/ogg` | ogg |
12
+ | `audioMessage` (ptt=false) | `audio` | `audio/mpeg` | mp3, m4a, aac, ogg |
13
+ | `documentMessage` | `document` | `application/octet-stream` | pdf, doc, docx, xls, xlsx, txt, etc. |
14
+ | `stickerMessage` | `image` | `image/webp` | webp |
15
+
16
+ ## Data Flow
17
+
18
+ ```
19
+ WAMessage (Baileys)
20
+
21
+
22
+ detectWhatsAppMedia(msg.message)
23
+
24
+ ├─▶ null (no media)
25
+
26
+
27
+ WhatsAppMediaInfo { type, mimeType, fileLength?, filename? }
28
+
29
+
30
+ downloadWhatsAppMedia(msg, sock, options)
31
+
32
+ ├─▶ null (too large / download failed)
33
+
34
+
35
+ MessageAttachment { path, type, mimeType, sizeBytes?, filename? }
36
+
37
+
38
+ Saved to: {workspace}/inbox/{timestamp}-{type}.{ext}
39
+ ```
40
+
41
+ ## Implementation
42
+
43
+ ### Detection
44
+
45
+ ```typescript
46
+ // src/adapters/whatsapp-media.ts
47
+ function detectWhatsAppMedia(message: proto.IMessage): WhatsAppMediaInfo | null
48
+ ```
49
+
50
+ Checks message for media fields in order:
51
+ 1. `audioMessage?.ptt` → voice note
52
+ 2. `audioMessage` → audio
53
+ 3. `imageMessage` → image
54
+ 4. `videoMessage` → video
55
+ 5. `documentMessage` → document
56
+ 6. `stickerMessage` → image
57
+
58
+ ### Download
59
+
60
+ ```typescript
61
+ // src/adapters/whatsapp-media.ts
62
+ async function downloadWhatsAppMedia(
63
+ msg: WAMessage,
64
+ sock: WASocket,
65
+ options: MediaDownloadOptions,
66
+ ): Promise<MessageAttachment | null>
67
+ ```
68
+
69
+ Uses Baileys' `downloadMediaMessage()`:
70
+
71
+ ```typescript
72
+ const buffer = await downloadMediaMessage(
73
+ msg,
74
+ "buffer",
75
+ {},
76
+ {
77
+ logger: silentLogger,
78
+ reuploadRequest: sock.updateMediaMessage,
79
+ },
80
+ );
81
+ ```
82
+
83
+ ### Adapter Integration
84
+
85
+ ```typescript
86
+ // src/adapters/whatsapp.ts
87
+ createWhatsAppBaileysAdapter({
88
+ mediaEnabled: true,
89
+ mediaMaxSizeBytes: 10 * 1024 * 1024,
90
+ getWorkspace: (spaceId) => ensureSpaceWorkspace(spacesDir, spaceId),
91
+ });
92
+ ```
93
+
94
+ ## Size Limits
95
+
96
+ Files are checked against `mediaMaxSizeBytes` twice:
97
+
98
+ 1. **Before download** — using `fileLength` from message metadata (may be missing)
99
+ 2. **After download** — using actual buffer size
100
+
101
+ Files exceeding the limit are logged and skipped:
102
+
103
+ ```
104
+ [WARN] Skipping large media file messageId=ABC type=video sizeBytes=52428800 maxBytes=10485760
105
+ ```
106
+
107
+ ## Reply Context
108
+
109
+ When replying to a message with media, the reply context includes media info:
110
+
111
+ ```typescript
112
+ // Attributes added to <reply_to>
113
+ media_type="image"
114
+ media_mime="image/jpeg"
115
+ ```
116
+
117
+ Example:
118
+ ```xml
119
+ <reply_to name="John" jid="123@wa" message_id="ABC" media_type="image" media_mime="image/jpeg">
120
+ [image]
121
+ </reply_to>
122
+ ```
123
+
124
+ ## File Naming
125
+
126
+ Pattern: `{timestamp}-{type}.{ext}` or `{timestamp}-{filename}` for documents
127
+
128
+ | Input | Output |
129
+ |-------|--------|
130
+ | image/jpeg | `1709012345-image.jpg` |
131
+ | audio/ogg (voice) | `1709012345-voice.ogg` |
132
+ | application/pdf, "report.pdf" | `1709012345-report.pdf` |
133
+
134
+ ## MIME to Extension Mapping
135
+
136
+ ```typescript
137
+ const MIME_TO_EXT: Record<string, string> = {
138
+ "image/jpeg": "jpg",
139
+ "image/png": "png",
140
+ "image/gif": "gif",
141
+ "image/webp": "webp",
142
+ "audio/ogg": "ogg",
143
+ "audio/mpeg": "mp3",
144
+ "audio/mp4": "m4a",
145
+ "video/mp4": "mp4",
146
+ "video/3gpp": "3gp",
147
+ "application/pdf": "pdf",
148
+ // ... etc
149
+ };
150
+ ```
151
+
152
+ Unknown MIME types default to `.bin`.
153
+
154
+ ## Limitations
155
+
156
+ 1. **No re-download** — Media is downloaded once when the message arrives. If the file is deleted, it's gone.
157
+
158
+ 2. **No transcription** — Voice notes are saved as audio files. pi cannot play them. Future: add Whisper transcription.
159
+
160
+ 3. **Reply context doesn't include file** — When replying to a media message, we include metadata but not the actual file path. The original attachment would need to be looked up.
161
+
162
+ 4. **Ephemeral media** — WhatsApp media URLs expire. Download must happen immediately when the message arrives.
163
+
164
+ ## Error Handling
165
+
166
+ | Error | Behavior |
167
+ |-------|----------|
168
+ | Download fails | Log error, continue without attachment |
169
+ | Buffer empty | Log error, return null |
170
+ | Size exceeded | Log warning, discard buffer |
171
+ | Write fails | Throw error (propagates up) |
package/docs/memory.md CHANGED
@@ -1,137 +1,137 @@
1
- # Memory
2
-
3
- Mercury stores memory per **space** in the space workspace directory. Memory behavior is extension-driven (for example, via a napkin extension).
4
-
5
- ## How It Works
6
-
7
- Each space gets a workspace at:
8
-
9
- ```text
10
- .mercury/spaces/<space-id>/
11
- ```
12
-
13
- Core directories Mercury manages:
14
-
15
- ```text
16
- .mercury/spaces/<space-id>/
17
- ├── inbox/ # Media received from users
18
- ├── outbox/ # Files produced by the agent
19
- ├── AGENTS.md # Space instructions
20
- └── .mercury.session.jsonl
21
- ```
22
-
23
- Additional vault structure (for example `.obsidian/`, `knowledge/`, `daily/`, `entities/`) is created by installed extensions.
24
-
25
- ## Vault Structure
26
-
27
- There is no single required memory schema in core Mercury. The exact structure depends on your extension setup.
28
-
29
- A common pattern (napkin example) is:
30
-
31
- ```text
32
- knowledge/
33
- ├── people/
34
- ├── projects/
35
- ├── references/
36
- └── daily/
37
- ```
38
-
39
- Conversations do not get their own vaults — multiple platform conversations can link into the same space.
40
-
41
- ## Agent Capabilities
42
-
43
- The agent discovers extension commands via installed skills (for example `napkin` skill in `.mercury/extensions/napkin/skill/`).
44
-
45
- ### Reading
46
-
47
- ```bash
48
- napkin search "query" # Find relevant files
49
- napkin read "filename" # Read a specific file
50
- napkin link back --file "name" # See what links to a file
51
- napkin daily read # Read today's daily note
52
- ```
53
-
54
- ### Writing
55
-
56
- ```bash
57
- napkin create --name "Liat" --path entities --content "..."
58
- napkin append --file "Liat" --content "..."
59
- napkin property set --file "Liat" --name birthday --value "April 15"
60
- napkin daily append --content "- Discussed vacation plans"
61
- ```
62
-
63
- ### Wikilinks
64
-
65
- The agent uses `[[wikilinks]]` when mentioning entities. This creates a navigable graph:
66
-
67
- ```markdown
68
- ---
69
- type: person
70
- relationship: wife
71
- ---
72
-
73
- # Liat
74
-
75
- [[Michael]]'s wife. Planning a surprise party at [[Dizengoff Italian Place]].
76
- ```
77
-
78
- ## User Interaction
79
-
80
- Users manage memory through natural chat:
81
-
82
- | User says | What happens |
83
- |-----------|--------------|
84
- | "Remember that Liat's birthday is April 15" | Agent writes to `entities/Liat.md` |
85
- | "What do you know about Liat?" | Agent reads and summarizes the entity file |
86
- | "Forget everything about the project" | Agent deletes the entity file |
87
-
88
- ## Entity Format
89
-
90
- Entities are markdown files with optional YAML frontmatter:
91
-
92
- ```markdown
93
- ---
94
- type: person
95
- birthday: April 15
96
- ---
97
-
98
- # Liat
99
-
100
- Context and notes about Liat.
101
-
102
- _2026-02-20:_ Booked the Italian place for April 12.
103
- _2026-02-25:_ Changed venue to [[Cafe Nimrod]].
104
- ```
105
-
106
- - **Frontmatter** — Structured attributes (replace semantics)
107
- - **Body** — Accumulated context (append semantics, timestamped)
108
- - **Wikilinks** — Connections to other entities
109
-
110
- ## Conditional Context
111
-
112
- Mercury can skip loading the full session for standalone prompts (e.g. "what's 2+2?"), reducing token usage. After the run, the prompt and reply are merged back into the session so history stays complete.
113
-
114
- See [conditional-context.md](conditional-context.md) for details and configuration.
115
-
116
- ## Persistence
117
-
118
- Memory persists because the agent writes to disk during conversation. When a session compacts or restarts, the vault files remain — the agent reads them fresh on next interaction.
119
-
120
- The vault is plain markdown. You can:
121
- - Open it in Obsidian and browse the graph
122
- - Edit files directly from the host
123
- - Back it up like any other directory
124
-
125
- ## Space preferences (built-in)
126
-
127
- Short, structured **per-space** hints (sources, habits, rules) can be stored in SQLite and managed from chat via `mrctl prefs` (see the built-in **preferences** skill). The host injects them into each run as a `<preferences>` block in the user prompt. See [prd-chat-memory.md](prd-chat-memory.md).
128
-
129
- ## Configuration
130
-
131
- Memory behavior is controlled by installed extensions and their config.
132
-
133
- To use a shared Obsidian vault across tools, symlink or mount it:
134
-
135
- ```bash
136
- ln -s /path/to/your/vault .mercury/spaces/main
137
- ```
1
+ # Memory
2
+
3
+ Mercury stores memory per **space** in the space workspace directory. Memory behavior is extension-driven (for example, via a napkin extension).
4
+
5
+ ## How It Works
6
+
7
+ Each space gets a workspace at:
8
+
9
+ ```text
10
+ .mercury/spaces/<space-id>/
11
+ ```
12
+
13
+ Core directories Mercury manages:
14
+
15
+ ```text
16
+ .mercury/spaces/<space-id>/
17
+ ├── inbox/ # Media received from users
18
+ ├── outbox/ # Files produced by the agent
19
+ ├── AGENTS.md # Space instructions
20
+ └── .mercury.session.jsonl
21
+ ```
22
+
23
+ Additional vault structure (for example `.obsidian/`, `knowledge/`, `daily/`, `entities/`) is created by installed extensions.
24
+
25
+ ## Vault Structure
26
+
27
+ There is no single required memory schema in core Mercury. The exact structure depends on your extension setup.
28
+
29
+ A common pattern (napkin example) is:
30
+
31
+ ```text
32
+ knowledge/
33
+ ├── people/
34
+ ├── projects/
35
+ ├── references/
36
+ └── daily/
37
+ ```
38
+
39
+ Conversations do not get their own vaults — multiple platform conversations can link into the same space.
40
+
41
+ ## Agent Capabilities
42
+
43
+ The agent discovers extension commands via installed skills (for example `napkin` skill in `.mercury/extensions/napkin/skill/`).
44
+
45
+ ### Reading
46
+
47
+ ```bash
48
+ napkin search "query" # Find relevant files
49
+ napkin read "filename" # Read a specific file
50
+ napkin link back --file "name" # See what links to a file
51
+ napkin daily read # Read today's daily note
52
+ ```
53
+
54
+ ### Writing
55
+
56
+ ```bash
57
+ napkin create --name "Liat" --path entities --content "..."
58
+ napkin append --file "Liat" --content "..."
59
+ napkin property set --file "Liat" --name birthday --value "April 15"
60
+ napkin daily append --content "- Discussed vacation plans"
61
+ ```
62
+
63
+ ### Wikilinks
64
+
65
+ The agent uses `[[wikilinks]]` when mentioning entities. This creates a navigable graph:
66
+
67
+ ```markdown
68
+ ---
69
+ type: person
70
+ relationship: wife
71
+ ---
72
+
73
+ # Liat
74
+
75
+ [[Michael]]'s wife. Planning a surprise party at [[Dizengoff Italian Place]].
76
+ ```
77
+
78
+ ## User Interaction
79
+
80
+ Users manage memory through natural chat:
81
+
82
+ | User says | What happens |
83
+ |-----------|--------------|
84
+ | "Remember that Liat's birthday is April 15" | Agent writes to `entities/Liat.md` |
85
+ | "What do you know about Liat?" | Agent reads and summarizes the entity file |
86
+ | "Forget everything about the project" | Agent deletes the entity file |
87
+
88
+ ## Entity Format
89
+
90
+ Entities are markdown files with optional YAML frontmatter:
91
+
92
+ ```markdown
93
+ ---
94
+ type: person
95
+ birthday: April 15
96
+ ---
97
+
98
+ # Liat
99
+
100
+ Context and notes about Liat.
101
+
102
+ _2026-02-20:_ Booked the Italian place for April 12.
103
+ _2026-02-25:_ Changed venue to [[Cafe Nimrod]].
104
+ ```
105
+
106
+ - **Frontmatter** — Structured attributes (replace semantics)
107
+ - **Body** — Accumulated context (append semantics, timestamped)
108
+ - **Wikilinks** — Connections to other entities
109
+
110
+ ## Conditional Context
111
+
112
+ Mercury can skip loading the full session for standalone prompts (e.g. "what's 2+2?"), reducing token usage. After the run, the prompt and reply are merged back into the session so history stays complete.
113
+
114
+ See [conditional-context.md](conditional-context.md) for details and configuration.
115
+
116
+ ## Persistence
117
+
118
+ Memory persists because the agent writes to disk during conversation. When a session compacts or restarts, the vault files remain — the agent reads them fresh on next interaction.
119
+
120
+ The vault is plain markdown. You can:
121
+ - Open it in Obsidian and browse the graph
122
+ - Edit files directly from the host
123
+ - Back it up like any other directory
124
+
125
+ ## Space preferences (built-in)
126
+
127
+ Short, structured **per-space** hints (sources, habits, rules) can be stored in SQLite and managed from chat via `mrctl prefs` (see the built-in **preferences** skill). The host injects them into each run as a `<preferences>` block in the user prompt. See [prd-chat-memory.md](prd-chat-memory.md).
128
+
129
+ ## Configuration
130
+
131
+ Memory behavior is controlled by installed extensions and their config.
132
+
133
+ To use a shared Obsidian vault across tools, symlink or mount it:
134
+
135
+ ```bash
136
+ ln -s /path/to/your/vault .mercury/spaces/main
137
+ ```