@wirecat/cli-memo 0.15.0 → 0.17.0

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 (45) hide show
  1. package/README.md +314 -299
  2. package/dist/knowledge/command.d.ts.map +1 -1
  3. package/dist/knowledge/command.js +3 -1
  4. package/dist/knowledge/command.js.map +1 -1
  5. package/dist/knowledge/meeting-projects-command.d.ts +4 -0
  6. package/dist/knowledge/meeting-projects-command.d.ts.map +1 -0
  7. package/dist/knowledge/meeting-projects-command.js +44 -0
  8. package/dist/knowledge/meeting-projects-command.js.map +1 -0
  9. package/dist/mcp/server.d.ts +1 -10
  10. package/dist/mcp/server.d.ts.map +1 -1
  11. package/dist/mcp/server.js +6 -1
  12. package/dist/mcp/server.js.map +1 -1
  13. package/dist/mcp/task-relations.d.ts +6 -0
  14. package/dist/mcp/task-relations.d.ts.map +1 -0
  15. package/dist/mcp/task-relations.js +30 -0
  16. package/dist/mcp/task-relations.js.map +1 -0
  17. package/dist/mcp/tool.d.ts +17 -0
  18. package/dist/mcp/tool.d.ts.map +1 -0
  19. package/dist/mcp/tool.js +2 -0
  20. package/dist/mcp/tool.js.map +1 -0
  21. package/dist/mcp/vocabulary.d.ts +7 -0
  22. package/dist/mcp/vocabulary.d.ts.map +1 -0
  23. package/dist/mcp/vocabulary.js +50 -0
  24. package/dist/mcp/vocabulary.js.map +1 -0
  25. package/dist/program.d.ts.map +1 -1
  26. package/dist/program.js +2 -0
  27. package/dist/program.js.map +1 -1
  28. package/dist/tasks/command.d.ts.map +1 -1
  29. package/dist/tasks/command.js +10 -2
  30. package/dist/tasks/command.js.map +1 -1
  31. package/dist/tasks/relations-command.d.ts +4 -0
  32. package/dist/tasks/relations-command.d.ts.map +1 -0
  33. package/dist/tasks/relations-command.js +51 -0
  34. package/dist/tasks/relations-command.js.map +1 -0
  35. package/dist/version.d.ts +1 -1
  36. package/dist/version.js +1 -1
  37. package/dist/vocabulary/command.d.ts +4 -0
  38. package/dist/vocabulary/command.d.ts.map +1 -0
  39. package/dist/vocabulary/command.js +96 -0
  40. package/dist/vocabulary/command.js.map +1 -0
  41. package/dist/vocabulary/project.d.ts +3 -0
  42. package/dist/vocabulary/project.d.ts.map +1 -0
  43. package/dist/vocabulary/project.js +17 -0
  44. package/dist/vocabulary/project.js.map +1 -0
  45. package/package.json +4 -4
package/README.md CHANGED
@@ -1,379 +1,390 @@
1
- # cli-memo
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/WireCatLabs/cli-memo/main/docs/images/social-preview.png" alt="Local knowledge for your AI agents" width="100%">
3
+ </p>
4
+
5
+ <h1 align="center">memo</h1>
6
+
7
+ <p align="center">
8
+ <strong>Local knowledge for your AI agents.</strong><br>
9
+ Your notes, documents, mail and messages in one local store — linked to people, tagged, and searchable
10
+ with a reference to every source.
11
+ </p>
12
+
13
+ <p align="center">
14
+ <a href="https://github.com/WireCatLabs/cli-memo/tree/main/docs">Docs</a> ·
15
+ <a href="#what-can-you-do">Examples</a> ·
16
+ <a href="https://wirecat.dev">WireCat</a>
17
+ </p>
18
+
19
+ <p align="center">
20
+ <a href="https://www.npmjs.com/package/@wirecat/cli-memo"><img alt="npm" src="https://img.shields.io/npm/v/@wirecat/cli-memo"></a>
21
+ <a href="https://github.com/WireCatLabs/cli-memo/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@wirecat/cli-memo"></a>
22
+ <img alt="Node" src="https://img.shields.io/node/v/@wirecat/cli-memo">
23
+ </p>
24
+
25
+ `memo` is a command-line tool. It imports a folder of notes such as an Obsidian vault, the documents in
26
+ it, and your mail; it reads the messages that [tg-cli](https://github.com/WireCatLabs/tg-cli) and
27
+ [max-cli](https://github.com/WireCatLabs/max-cli) keep. Then you, or your AI agent, ask: what do I know
28
+ about this person, where did we discuss this, what did I promise. Every answer points back to its source.
29
+
30
+ <!-- Demo slot: a 30–45 s recording of an agent answering "What did I promise Alice?" from memo, with
31
+ sources. Add it here once recorded; until then the example below shows the real output. -->
32
+
33
+ **Example** — two invented notes in a vault, `people/Alice Example.md` and `Projects/Harbour budget.md`:
34
+
35
+ ```text
36
+ $ memo search notes budget Friday
37
+ Projects/Harbour budget.md
38
+ # Harbour budget
39
+ people/Alice Example.md
40
+ Asked for the revised budget by Friday. See [[Harbour budget]].
41
+
42
+ Linked from these notes
43
+ Alice Example document:2 (1)
44
+ Bob Sample (nobody by that name yet) (1)
45
+ Harbour budget document:1 (1)
46
+ ```
2
47
 
3
- `memo` answers "what do I need to know about this person": who they are in each messenger, the
4
- newest messages each way, the notes about them, and the newest mail threads — each item with a link
5
- to its source.
48
+ Each hit names its file, and `[[links]]` become links to notes and people. `Bob Sample` becomes a link to
49
+ a person once someone by that name is in the store.
6
50
 
7
- It reads the local message store that [tg-cli](https://github.com/WireCatLabs/tg-cli) and
8
- [max-cli](https://github.com/WireCatLabs/max-cli) share, Markdown notes such as an Obsidian vault, and mail
9
- through [Himalaya](https://github.com/pimalaya/himalaya). Source files and mailboxes are read-only.
10
- Notes you write here, links, labels, relationships and task reminders live in the local store.
11
- Retrieval is local; an explicitly selected model receives evidence only with the configured consent.
51
+ ## Quick start
12
52
 
13
- **Status:** early. Context, notes and their links, document import, Gmail and IMAP imports, tasks,
14
- manual relationships, evidence bundles and local reminders work.
15
-
16
- ## Your notes on messages, people and projects
53
+ You need Node.js 22.16 or newer.
17
54
 
18
55
  ```sh
19
- memo notes add 'Prefers mornings' --about telegram:'Rin Example'
20
- memo notes add --file review.md --about 'msg:telegram/1/77/42' --about project:PROJECT_ID --export
21
- memo notes list --about telegram:'Rin Example' --json
22
- memo notes edit NOTE_ID --revision 1 --text 'Prefers early mornings'
23
- memo notes remove NOTE_ID
24
- memo notes export --to /path/to/vault/memo --format obsidian
56
+ npm install -g @wirecat/cli-memo
57
+ memo folders add /path/to/notes # your notes folder; Obsidian format by default
58
+ memo notes import # reads the notes, their links and tags; run again after edits
59
+ memo search notes "budget"
25
60
  ```
26
61
 
27
- A note written here is the store's, not a file's, and is about whatever `--about` names: a person by
28
- `<messenger>:<name or id>`, or any stored record by its reference — `msg:`, `chat:`, `contact:`,
29
- `person:`, `organization:`, `project:`, `task:`, `note:`, `document:`. Several `--about` give it several
30
- subjects. An edit names the
31
- revision it changes, so an edit made meanwhile is never lost. tg and max `contacts notes` are the same
32
- notes.
62
+ That is all notes need. Then add more context:
33
63
 
34
- `export` writes them as files, in a folder's format, with `memo-id` and `memo-hash` in the front
35
- matter: import skips such a file, so an export inside a vault never comes back as a second note. A
36
- file edited since memo wrote it is left alone and reported; nothing is deleted. `--export [dir]` on `add`
37
- and `edit` writes one; with no folder given, `notes.export: { "dir": "…", "format": "…" }` in the
38
- config says where.
64
+ - **Messages:** install [tg-cli](https://github.com/WireCatLabs/tg-cli) or
65
+ [max-cli](https://github.com/WireCatLabs/max-cli); memo reads the same local store.
66
+ - **Search by meaning:** `tg models text download e5-small` downloads the local model once.
67
+ - **Mail:** set up [Himalaya](https://github.com/pimalaya/himalaya), then `memo mail <account> import`.
68
+ - **Stay current:** `memo auto on` runs `memo import` every five minutes (Linux, systemd).
39
69
 
40
- ## Open work
70
+ Or ask your agent: "Help me install memo with `npm install -g @wirecat/cli-memo`, read `memo --help`, then
71
+ help me connect a notes folder I choose."
41
72
 
42
- ```sh
43
- memo tasks add 'msg:telegram/1/77/42' --type request
44
- memo tasks add 'note:NOTE_ID' --provider telegram --account 1 --type request
45
- memo tasks list --provider telegram --account 1 --json
46
- memo tasks assign TASK_ID PERSON_UID --role reviewer
47
- memo tasks close TASK_ID --provider telegram --account 1 --as done
48
- memo tasks add --project LH --title 'Export drops the last row' --type bug --priority 1 --assignee PERSON_UID
49
- memo tasks update LH-1 --priority 0 --description 'Seen on CSV export'
50
- memo tasks list --project LH
51
- memo tasks close LH-1 --reason fixed
52
- ```
73
+ More: [installation](https://github.com/WireCatLabs/cli-memo/blob/main/docs/installation.md) ·
74
+ [install memo on wirecat.dev](https://wirecat.dev/en/docs/memo#install-memo)
53
75
 
54
- A bug, feature or chore has no source: `--project` (its key or `project:<id>`) and `--title` make it there,
55
- keyed `<project key>-<n>`. `--priority` (0 urgent … 4 low), `--parent`, `--description` and `--assignee` work
56
- on any task, one from a message too; `tasks update` changes them later. `tasks assign` names an assignee,
57
- reviewer or watcher. Every change of status, due date, priority or assignee is recorded as a task event.
76
+ ## What can you do?
58
77
 
59
- Native note tasks belong to the explicitly selected stored account. Their previews read current note
60
- text; deleting a note keeps its task with an unavailable source. Repeated creation of the same kind
61
- returns the existing task, including one already closed.
78
+ **"What do I need to know about Alice before the call?"**
62
79
 
63
- `context` includes directly related open tasks and explicit task assignments. A task in a shared group
64
- belongs in a person's context only when they authored its source or you assigned it explicitly. Closed
65
- tasks stay closed on repeated creation. If several accounts of the requested provider exist, use
66
- `memo context telegram:101 --account 1`.
80
+ ```sh
81
+ memo context telegram:"Alice Example" --json
82
+ ```
83
+
84
+ Every identity linked to her, the last message each way, chats in common, linked mail, the notes about
85
+ her and the open tasks — each with a link to its source.
67
86
 
68
- ## Search and gather evidence
87
+ **"Where did we discuss the Harbour budget?"**
69
88
 
70
89
  ```sh
71
- memo search notes '"budget review" AND NOT cancelled' --limit 20
72
- memo search notes 'project progress' --filter 'date:2026-10-08' --tag project --folder /path/to/vault
73
- memo notes show note:NOTE_ID --json
74
- memo search all 'budget AND date:[2026-09-01 TO *]' --json
75
- memo ask 'What work is pending?' --query budget --all --json
90
+ memo search all 'harbour budget' --json
76
91
  ```
77
92
 
78
- Notes are searched by their words and word stems, in the query language messages use: phrases,
79
- `AND`/`OR`/`NOT`, `tag:`, `date:`; `--exact` matches every word as written. A message-only field such as
80
- `from:` is refused. They are also searched by meaning when the model is downloaded, and the two are
81
- ranked together: `by` says which ran, each hit's `foundBy` which found it, and `meaningSkipped` why
82
- meaning did not run. Each hit carries its reference, the first matching line and the links the note
83
- holds; `linked` counts what the notes found link to, with each person's name. Follow `nextOffset` with
84
- `--offset`.
85
-
86
- `notes show` takes `note:<id>` or a file in a configured folder, and answers with the note's tags, its
87
- links, its backlinks and, for a PDF or sheet, where its text came from.
88
-
89
- `search all` searches messages, imported mail and native notes together, and nothing else: not people,
90
- memories, projects, organizations or decisions. Use it when you do not know where something was written. When
91
- you know the kind, its own search reads it with every field: `search mail` takes `from:`, `to:`, `cc:`, `bcc:`,
92
- `subject:` and `mailbox:` (a folder or Gmail label); `search messages`, `search notes`; `search notes --type
93
- internal|file` narrows note kinds. An empty answer means those three hold nothing that matches: try the kind's
94
- own search, looser words, or `tg search conversations` to find mail and messages by meaning.
95
- `search all` includes a separate `tasks` list for open work linked to matching sources. Results identify source
96
- kind/account and skipped-resource coverage; a query using a field only messages have (`from:`, `after:`)
97
- searches the messages and says the notes were not searched. Missing hits do not prove that an event
98
- never happened.
99
-
100
- `ask` returns an evidence bundle for your chosen agent by default. To call a model, configure
101
- `MEMO_MODELS_ANALYSIS_PROVIDER`, `MEMO_MODELS_ANALYSIS_MODEL`, optionally
102
- `MEMO_MODELS_ANALYSIS_BASE_URL` and `MEMO_MODEL_API_KEY`, then pass `--model`. Remote calls also require
103
- `--allow-remote`. Model claims are generated and unverified, cite supplied evidence, and distinguish
104
- assertions, conclusions and inferences. Suggestions create no task until you explicitly run
105
- `memo tasks add <source> --type <kind>`. Answers are not saved as independent facts.
106
-
107
- ## Organizations and projects
93
+ Messages, imported mail and notes, ranked together. When you know the kind, `search notes`,
94
+ `search mail` and `search messages` read every field.
95
+
96
+ **"What did I promise people this week?"**
108
97
 
109
98
  ```sh
110
- memo organizations add 'Synthetic Studio' --kind company
111
- memo projects add 'Synthetic Harbour' --organization organization:ORGANIZATION_ID
112
- memo relationships add person:PERSON_UID project:PROJECT_ID --role author
113
- memo projects context PROJECT_ID --json
114
- memo tags add client --organization ORGANIZATION_ID
115
- memo tags add follow-up --task TASK_ID
99
+ memo ask 'What did I promise this week?' --query 'promised OR "by Friday"' --all --json
116
100
  ```
117
101
 
118
- Organizations (a company, team, family or community) and projects (with a short key, a type and the
119
- organization they belong to) are yours, not one account's. Relationships use `member-of` or `related-to`;
120
- `list`, `remove` and `confirm` manage them. They are manual statements and never merge identities because
121
- names or domains match. `organizations context` and `projects context` list the relationships, the notes
122
- about or linking it, and its tags. Tags on a task need no account; its
123
- reminders name the account it waits on.
102
+ An evidence bundle for your agent: the matching sources with their references, what was searched, and
103
+ the instruction to cite them. Your agent writes the answer; memo calls a model only when you ask it to.
124
104
 
125
- `memo relationships suggest --provider email --account owner@example.test` stores bounded weak
126
- shared-domain proposals for direct email contacts. Proposals retain rule provenance and remain
127
- unconfirmed; they do not enter confirmed person context. `relationships confirm <id>` records your
128
- explicit acceptance. Common free-mail domains are excluded from this heuristic.
105
+ More: [search and evidence](https://github.com/WireCatLabs/cli-memo/blob/main/docs/search.md) ·
106
+ [ask for the context you need](https://wirecat.dev/en/docs/memo#ask-for-the-context-you-need)
129
107
 
130
- ## Memories, proposed actions and the agent log
108
+ ## Built for AI agents
131
109
 
132
- ```sh
133
- memo memories add 'Bob Sample prefers Friday meetings' --kind preference --scope work --evidence note:NOTE_ID
134
- memo memories list --status proposed
135
- memo memories confirm memory:MEMORY_ID
136
- memo facts add 'Releases go out on Fridays' --type decision --evidence msg:telegram/1/77/42
137
- memo facts list --type decision --status proposed
138
- memo facts accept fact:FACT_ID
139
- memo actions propose reply --reason 'asked twice' --provider telegram --payload '{"text":"Friday works"}'
140
- memo actions approve ACTION_ID
141
- memo agents log --agent memo-mcp --limit 20
142
- ```
110
+ - **Any agent with a terminal** — Claude Code, Codex, Gemini CLI and others run `memo` commands; `--json`
111
+ gives them structured output.
112
+ - **Evidence, not guesses** — `memo ask` hands over sources with references, and says what it could not
113
+ search.
114
+ - **MCP** — `memo mcp` lets MCP apps such as Claude Desktop or Cursor propose memories, facts and actions
115
+ and read the agent log; they wait for you to confirm.
143
116
 
144
- A memory is what was concluded — a summary, digest or preference — with its evidence (any stored reference)
145
- and a scope, `personal` or `work`. One you write is confirmed at once; an agent's waits as `proposed` until you
146
- `confirm` it, and `stale` marks one whose evidence no longer holds. `memories search` finds the words in
147
- them.
117
+ More: [connect your AI agent](https://wirecat.dev/en/docs/agents) ·
118
+ [memories, proposed actions and MCP](https://github.com/WireCatLabs/cli-memo/blob/main/docs/mcp.md)
148
119
 
149
- A fact is what happened: a fact, a statement, a question, a decision or a promise, with its evidence. Yours is
150
- accepted at once; an agent's waits as `proposed` until you `facts accept` it. A decision with `--supersedes`
151
- ends the one it replaces once accepted, and `facts reverse` ends an accepted decision nothing replaced.
120
+ ## Why memo?
152
121
 
153
- A proposed action is what an agent wants done in one account: a reply, a ban, an invitation. Nothing is ever
154
- sent. `actions approve` makes it a task in that account's inbox, so it shows in `memo tasks list`, and the
155
- proposal remembers the task; `actions reject` closes it. `actions list --status` filters them.
122
+ 1. **Local first.** Everything lives in a local store; search by meaning uses a local model.
123
+ 2. **Every answer has a source.** Hits carry a reference you or your agent can open: a note, a file
124
+ page, an email, a message.
125
+ 3. **Links, not guesses.** Notes link to people and records; identities are never merged because a name
126
+ matches.
127
+ 4. **Your sources stay untouched.** Folders and mailboxes are read-only; tags and your own notes live in
128
+ the store.
129
+ 5. **Agents propose, you decide.** Memories and actions an agent suggests wait for your confirmation;
130
+ nothing is ever sent.
156
131
 
157
- `memo agents log` lists what agents did through the MCP servers that share the store, newest first: the
158
- agent, the tool, its tier, the outcome and the times, never the arguments.
132
+ **Status:** early. Context, notes and their links, document import, Gmail and IMAP imports, tasks,
133
+ manual relationships, evidence bundles and local reminders work.
159
134
 
160
- `memo mcp` serves the same to an agent over MCP, on stdin and stdout: `memories_add`, `memories_list`,
161
- `memories_show`, `memories_search`, `facts_add`, `facts_list`, `facts_show`, `actions_propose`, `actions_list`, `actions_show` and `agents_log`. An
162
- agent's memories, facts and proposals are its own (`memo-mcp`) and wait for you; it cannot confirm, accept,
163
- approve or reject. Every call goes into the agent log.
135
+ More: [security](https://github.com/WireCatLabs/cli-memo/blob/main/docs/security.md) ·
136
+ [security on wirecat.dev](https://wirecat.dev/en/docs/security)
164
137
 
165
- ```json
166
- { "mcpServers": { "memo": { "command": "memo", "args": ["mcp"] } } }
167
- ```
138
+ ## What it reads
139
+
140
+ - **Folders of notes:** Obsidian or plain Markdown, with links, aliases and tags.
141
+ - **Documents in them:** TXT, CSV/TSV, text-layer PDF, DOCX, XLSX, ODT/ODS, PPTX and EPUB, with the page,
142
+ row or cell each passage came from.
143
+ - **Mail:** Gmail or another IMAP account, through Himalaya, attachments included.
144
+ - **Messages:** the tg and max store, with the people linked across messengers and mail.
145
+
146
+ You add your own notes about messages, people and projects, tags, tasks and reminders, organizations and
147
+ projects.
148
+
149
+ More: [notes](https://github.com/WireCatLabs/cli-memo/blob/main/docs/notes.md) ·
150
+ [files memo can read](https://wirecat.dev/en/docs/memo#files-memo-can-read)
168
151
 
169
- ## Local task reminders
152
+ ## Commands by task
153
+
154
+ | Task | Commands |
155
+ | --- | --- |
156
+ | Connect notes folders | `memo folders add` · `folders attach` · `folders list` |
157
+ | Import what changed | `memo import` · `notes import` · `mail <account> import` · `auto on` / `off` / `status` |
158
+ | Read notes | `memo notes list` · `notes show` · `notes about` · `memo note` (the note about a person) |
159
+ | Write your own notes | `memo notes add` · `notes edit` · `notes remove` · `notes export` |
160
+ | Search | `memo search all` · `search notes` · `search mail` · `search messages` |
161
+ | Hand evidence to an agent | `memo ask` |
162
+ | Know a person | `memo context` |
163
+ | Organizations and projects | `memo organizations add` / `list` / `context` · `projects add` / `list` / `context` · `projects meetings list` / `link` |
164
+ | Project and topic aliases | `memo vocabulary list` / `resolve` / `preflight` · `vocabulary aliases add` / `remove` · `vocabulary create` |
165
+ | Relationships | `memo relationships add` / `list` / `remove` / `confirm` / `suggest` |
166
+ | Labels | `memo tags add` · `tags remove` · `tags list` |
167
+ | Open work | `memo tasks add` · `tasks list` · `tasks update` · `tasks assign` · `tasks close` |
168
+ | Task dependencies | `memo tasks link` / `unlink` / `relations` · `tasks readiness` · `tasks ready` |
169
+ | Reminders | `memo reminders schedule` / `list` / `poll` / `ack` / `snooze` / `cancel` |
170
+ | Agents | `memo memories …` · `facts …` · `actions …` · `agents log` · `memo mcp` |
171
+
172
+ Every command takes `--help`; most take `--json`.
173
+
174
+ More: [technical docs](#technical-docs) · [notes and files on wirecat.dev](https://wirecat.dev/en/docs/memo)
175
+
176
+ ## Notes from files, and notes you write
177
+
178
+ **From a folder.** `memo folders add` gives a folder an id that the store uses; its path is only where it is
179
+ on this computer, so the same folder on another computer is attached with `memo folders attach <id> <path>`.
180
+ `memo notes import` stores each file as a note named by its path. An edited file keeps its old text as a
181
+ revision; a moved file keeps its id, links and tags; a deleted file loses its text on the next import. The
182
+ `obsidian` format (the default) reads `[[Note|label]]` links, aliases, `tags:` and `#tags`; `markdown` reads
183
+ `[label](path.md)` links and `tags:`. A `[[Kai Sample]]` link becomes a link to a person once someone by that
184
+ name is in the store. Hidden folders such as `.obsidian` are skipped.
185
+
186
+ **Written in memo.** A note you write is the store's, not a file's, and is about whatever `--about` names: a
187
+ person, a message, a chat, a project, a task, another note.
170
188
 
171
189
  ```sh
172
- memo reminders schedule TASK_ID --at 2026-10-09T09:00:00+02:00 --timezone Europe/Madrid --provider telegram --account 1
173
- memo reminders poll --provider telegram --account 1 --json
174
- memo reminders ack REMINDER_ID RECEIPT --provider telegram --account 1
175
- memo reminders snooze REMINDER_ID --revision 1 --at 2026-10-10T09:00:00+02:00 --provider telegram --account 1
176
- memo reminders cancel REMINDER_ID --provider telegram --account 1
190
+ memo notes add 'Prefers mornings' --about telegram:'Alice Example'
191
+ memo notes edit NOTE_ID --revision 1 --text 'Prefers early mornings'
192
+ memo notes export --to /path/to/vault/memo --format obsidian
177
193
  ```
178
194
 
179
- Reminders are local deliveries for an explicitly scheduled open task. Poll leases due deliveries;
180
- acknowledgement confirms consumption. Expired leases retry with a new receipt; integrations deduplicate
181
- by `deliveryId` (reminder ID and revision). State survives restart. Snooze checks the current revision;
182
- task closure cancels pending reminders. The import timer continues to import sources and does not
183
- deliver reminders to messengers or email. A caller can schedule `poll` using its chosen local scheduler.
195
+ An edit names the revision it changes, so an edit made meanwhile is never lost. `export` writes your notes
196
+ as files that import then skips, and never overwrites a file you edited.
197
+
198
+ More: [notes](https://github.com/WireCatLabs/cli-memo/blob/main/docs/notes.md) ·
199
+ [add your notes](https://wirecat.dev/en/docs/memo#add-your-notes) ·
200
+ [create your own notes](https://wirecat.dev/en/docs/memo#create-your-own-notes)
184
201
 
185
- ## Context about a person
202
+ ## Search and evidence
203
+
204
+ Notes are searched by words and word stems in the query language messages use — phrases, `AND`/`OR`/`NOT`,
205
+ `tag:`, `date:` — and by meaning once the local model is downloaded; both are ranked together. `search all`
206
+ reads messages, imported mail and notes together, and nothing else. When you know the kind, its own search
207
+ reads every field: `search mail` takes `from:`, `to:`, `cc:`, `bcc:`, `subject:` and `mailbox:`.
186
208
 
187
209
  ```sh
188
- memo context telegram:"Rin Example" # or max:<name or id>, email:<address>
210
+ memo search notes '"budget review" AND NOT cancelled' --limit 20
211
+ memo search mail 'from:alice@example.com subject:budget'
212
+ memo notes show note:NOTE_ID --json
189
213
  ```
190
214
 
191
- One answer from the shared store: every identity linked to the person (`tg|max contacts link`), the
192
- last message each way, recent messages in direct chats and groups, chats in common — mail included once
193
- an address is linked — then the notes linked to them: the note about them (`memo note`), notes that link
194
- them, notes that link the note about them, and the notes you wrote here about them. A name in a note's
195
- plain text is not a link and is not listed. What gave nothing is listed with the reason. `--json` for
196
- agents, `--limit` for more.
215
+ `memo ask` needs a scope (`--all`, or `--provider` with `--account`) and returns evidence by default. To
216
+ call a model instead, set `MEMO_MODELS_ANALYSIS_PROVIDER` and `MEMO_MODELS_ANALYSIS_MODEL` and pass
217
+ `--model`; a remote model also needs `--allow-remote`.
218
+
219
+ More: [search and evidence](https://github.com/WireCatLabs/cli-memo/blob/main/docs/search.md) ·
220
+ [searching on wirecat.dev](https://wirecat.dev/en/docs/search)
221
+
222
+ ## People, organizations and projects
197
223
 
198
- ## Notes
224
+ `memo context` answers from the shared store: every identity linked to the person, the last message each
225
+ way, recent messages, chats in common, linked mail, the notes about them and the open tasks. Who is who is
226
+ decided in messaging — `tg contacts link <person> email:<address>` — and a same name is never enough.
227
+ `memo note telegram:"Alice Example" /path/to/notes/people/Alice.md` names the note that is about her.
228
+
229
+ Organizations and projects are yours, not one account's. Relationships (`member-of`, `related-to`) are
230
+ manual statements; `relationships suggest` only proposes shared-domain links for you to confirm. A project
231
+ can hold meetings (`projects meetings link`), and `memo vocabulary` gives projects and topics reviewed
232
+ aliases, so one name always means one project.
233
+
234
+ Before adding a new tag or topic, run `memo vocabulary preflight <name> --json`. Reuse a
235
+ canonical label or add an alias if it means the same thing. For a deliberately distinct label,
236
+ run `memo vocabulary create <name> --expected <creationFingerprint> --json`; select `--kind topic`
237
+ on both commands when creating a topic. The owner accepts this review; MCP exposes preflight
238
+ but no label-creation tool. An intervening label or alias change requires a fresh review.
239
+ `memo vocabulary audit --json` finds likely synonyms already in the catalog. Its `complete`
240
+ flag reports whether the bounded comparison finished; candidates require review and are never
241
+ merged automatically. Use `--kind tag`, `--kind topic` or `--kind project` to narrow the review.
199
242
 
200
243
  ```sh
201
- memo folders add /path/to/vault # once: gives the folder an id
202
- memo notes import # load the notes into the shared store; run again after edits
203
- memo search notes "lighthouse budget" # notes by their words and meaning, and what they link
204
- memo notes about telegram:"Rin Example" # notes about a person, and the notes linking them
244
+ memo organizations add 'Synthetic Studio' --kind company
245
+ memo projects add 'Synthetic Harbour' --organization organization:ORGANIZATION_ID
246
+ memo projects context PROJECT_ID --json
205
247
  ```
206
248
 
207
- `import` stores each file as a note of its folder, named by its path inside the folder. An edited note
208
- keeps its old text as a revision; a note deleted from the folder loses its text on the next import, and a
209
- run that finds most notes missing at once deletes nothing and says so. A file moved inside the folder —
210
- gone from one path, the same content at another — keeps its id, its links and its tags.
211
-
212
- Import also stores what each note links, through the folder's format. A link to a note the folder has
213
- once becomes a link to that note. A name no note has, such as `[[Kai Sample]]`, is kept as written and
214
- becomes a link to the person the moment someone by that name, local alias or username is in the store —
215
- or stays unresolved while two people share it. A file's `tags:` and `#tags` become the note's tags, and
216
- a tag removed from the file is removed from the note — unless you added the same tag yourself.
217
-
218
- Import then embeds the notes for search by meaning with the local e5-small model (shared with tg and
219
- max: `tg models text download e5-small`), only what changed, at most 600 chunks a run — the next run
220
- continues. `--no-embed`, or `notes.embed: false` in the config, skips it.
221
-
222
- `about` takes `<messenger>:<name or id>` or a reference (`person:`, `organization:`, `project:`, `note:`,
223
- `document:`) and lists the
224
- notes about it, the notes that link it, the notes that link a note about it, and links written with the
225
- person's name that two people share. Hidden folders such as `.obsidian` are skipped, and nothing is ever
226
- written to a notes folder.
227
-
228
- Imports accept Markdown/TXT, CSV/TSV, text-layer PDF, DOCX, XLSX, ODT/ODS, PPTX and EPUB.
229
- PDF/DOCX use optional `unpdf` and `mammoth` packages installed alongside the CLI; modern office
230
- formats use the bounded built-in shared readers. Results report missing engines, unreadable files, unsupported legacy DOC/XLS, scanned
231
- PDFs needing an agent, oversized inputs and truncation. PDF page spans, CSV row/column ranges and
232
- XLSX sheet/cell addresses preserve source provenance. Files are capped at 50 MiB and stored text at
233
- 200,000 characters. Content hashes detect equal-size edits.
234
-
235
- Folders and what to skip go in `~/.config/cli-memo/config.json`; `--folder` narrows a run to some of the
236
- configured folders and `--ignore` adds rules for one run. An ignore rule is a path inside the folder — a file, or a folder and everything under it —
237
- or a glob (`**/Private*`, `*.txt`):
249
+ More: [people, organizations and projects](https://github.com/WireCatLabs/cli-memo/blob/main/docs/people.md) ·
250
+ [people on wirecat.dev](https://wirecat.dev/en/docs/people)
238
251
 
239
- ```json
240
- { "notes": { "folders": [{ "id": "3", "path": "/path/to/vault" }], "ignore": ["Journal/Private.md", "Archive"] } }
241
- ```
252
+ ## Mail
242
253
 
243
- ### Folders and their format
254
+ memo reads mail through [Himalaya](https://github.com/pimalaya/himalaya), a command-line mail client you
255
+ set up first. Gmail is the default; another IMAP provider uses `mode: "imap"` with the folders to read. The
256
+ mailbox is opened read-only, `--max` (default 200) bounds the new mail per run and the next run continues.
257
+ Gmail labels become mailboxes, attachments' text is searched with its email, and mail deleted at the
258
+ source loses its text in the store. Each account is named in `mail.accounts`, and the import names it:
259
+ memo never picks one for you. `memo import` and the timer import every account.
244
260
 
245
261
  ```sh
246
- memo folders add /path/to/vault # gives the folder an id and prints it
247
- memo folders add /path/to/notes --format markdown # a plain Markdown folder
248
- memo folders attach FOLDER_ID /other/path/to/vault # the same folder on another computer
249
- memo folders list
262
+ memo mail work import --since 2026-09-01 # work: the account's name in mail.accounts
263
+ memo search mail 'mailbox:important budget'
250
264
  ```
251
265
 
252
- A folder's id is the store's and is what notes and links use; its path is only where it is on this
253
- computer, so the config differs between computers and the id does not. `folders list` also shows the
254
- folders the store has from another computer, to attach. A path can belong to one id only. A bare path in
255
- `notes.folders`, or a folder with no id, is refused by import with both commands named — memo never
256
- invents an id, which would give every note a new identity. A folder id from a store older than
257
- `wirecat.db` is not in the store: `memo folders add <path>` gives the folder a new one.
266
+ More: [mail](https://github.com/WireCatLabs/cli-memo/blob/main/docs/mail.md) ·
267
+ [email on wirecat.dev](https://wirecat.dev/en/docs/email)
258
268
 
259
- `format` says how the folder's notes are written. `obsidian` (the default) reads `[[Note|label]]` links
260
- with `#heading` and `#^block` anchors, `aliases`, `tags:` and inline `#tags`. `markdown` reads
261
- `[label](path.md)` links and `tags:`; a `#word` in its text is not a tag. Both read links to stored
262
- records — `[Rin](person:…)`, or a bare `msg:…` in the text.
269
+ ## Tags, tasks and reminders
263
270
 
264
- A Markdown file whose front matter carries `memo-id` was written by memo and is skipped by import.
265
-
266
- ## Keeping it current
271
+ Tags are your labels on a note, an email, a message, a chat, a person, an organization, a project, a task,
272
+ a meeting, or every note under a folder. They live in the store; files, Gmail labels and mailbox flags are
273
+ never changed. A task points at the message or note it came from, or is your own in a
274
+ project (`--project RES --title …`), and can be blocked by another until it is done. Reminders are local:
275
+ a caller you choose polls for them, and nothing is delivered to a messenger or mailbox.
267
276
 
268
277
  ```sh
269
- memo import # notes and mail, only what changed since the last run
270
- memo auto on --every 5m # run memo import on a systemd user timer (default 5m, a minute or more)
271
- memo auto status # on/off, interval, next and last run
272
- memo auto off # stop and remove the timer
278
+ memo tags add follow-up --note note:NOTE_ID
279
+ memo tasks add 'msg:telegram/1/77/42' --type request
280
+ memo reminders schedule TASK_ID --at 2026-10-09T09:00:00+02:00 --provider telegram --account 1
273
281
  ```
274
282
 
275
- The config is the one source: `memo auto on/off` write `auto: { enabled, every }` to
276
- `~/.config/cli-memo/config.json`, and a hand edit there takes effect at the next timer run, which
277
- rewrites or removes its own timer to match. The timer runs `memo import` from the place it was set up
278
- from, with the `PATH` of that shell, so Himalaya and the keyring helper are found.
283
+ More: [tags](https://github.com/WireCatLabs/cli-memo/blob/main/docs/tags.md) ·
284
+ [open work and reminders](https://github.com/WireCatLabs/cli-memo/blob/main/docs/tasks.md) ·
285
+ [tag your sources](https://wirecat.dev/en/docs/memo#tag-your-sources)
279
286
 
280
- `memo import` is incremental. A note whose size and change time are as this computer last saw them is
281
- not read; one whose content hash the store already has is not saved, so a second computer importing the
282
- same folder saves nothing new. What this computer last saw is kept per folder in memo's state folder. Mail reads bodies only of messages not stored yet. A lock
283
- keeps two imports from running at once, and one failing source does not stop the others.
287
+ ## Agents and MCP
284
288
 
285
- ## Mail
289
+ An agent with a terminal runs `memo` with `--json`. An MCP app starts `memo mcp`, which serves memories,
290
+ facts, proposed actions and the agent log on stdin and stdout:
286
291
 
287
- Gmail remains the default. For another IMAP provider, configure an account with `mode: "imap"`
288
- and `folders: ["INBOX", "Archive"]` in `mail.accounts`. Message-ID and reference headers preserve
289
- message/thread identities across folder moves and UID resets. Mail without Message-ID uses an explicit
290
- UIDVALIDITY/folder/UID fallback, which can change after a move/reset. Configured folders are listed
291
- completely before deletion checks; a changed folder scope skips deletion for that run.
292
+ ```json
293
+ { "mcpServers": { "memo": { "command": "memo", "args": ["mcp"] } } }
294
+ ```
292
295
 
293
- Imports report the proven date/folder window. No thread is called globally complete on the basis of one
294
- window. To, CC and BCC are kept. A readable attachment's text is kept with its email and searched with it
295
- (`content:`, `filename:`); extraction failures are reported. After installing an optional engine, use
296
- `memo mail <account> import --retry-attachments` to reread a bounded batch of stored mail. Import embeds mail
297
- for search by meaning (`--no-embed` skips it); `memo search mail` itself matches words, and `tg search
298
- conversations` finds mail by meaning.
296
+ An agent's memories, facts and proposals wait as `proposed`; it cannot confirm, accept, approve or reject. Approving an
297
+ action makes it your task; nothing is ever sent. `memo agents log` lists every call — the agent, the tool,
298
+ the outcome and the times, never the arguments. Search and context are not served over MCP.
299
299
 
300
- ```sh
301
- memo mail work import --since 2026-09-01 # work: the account's name in mail.accounts
302
- memo search mail 'budget' --account you@example.com # one mail account; every one without --account
303
- ```
300
+ More: [memories, proposed actions and MCP](https://github.com/WireCatLabs/cli-memo/blob/main/docs/mcp.md) ·
301
+ [MCP on wirecat.dev](https://wirecat.dev/en/docs/mcp)
302
+
303
+ ## Keeping it current
304
304
 
305
- `<account>` is required, even with one account configured: memo never picks one for you, and names the
306
- configured accounts when it is missing or unknown. `memo import` and the timer import every account in
307
- `mail.accounts`. A mail import and `memo import` share one lock, so they never run at the same time.
305
+ `memo import` brings notes and mail up to date and reads only what changed. `memo auto on --every 5m` runs
306
+ it on a systemd user timer; `auto status` shows the next and last run. A lock keeps two imports apart, and
307
+ one failing source does not stop the others.
308
308
 
309
- Reads a Gmail account's All Mail through [Himalaya](https://github.com/pimalaya/himalaya) into the
310
- shared store's mail tables: one thread per Gmail thread, each folder a mailbox, the mailbox address as
311
- the account, senders and recipients as people. Gmail labels (Inbox, Important, Starred, your own) become
312
- label mailboxes, so `search mail mailbox:important` finds them. `search mail`, `search all`, `ask`, person context and tags
313
- see it. Mail an import before 0.8.0 saved as messages stays searchable; an email imported again is listed
314
- once.
309
+ More: [keeping the store current](https://github.com/WireCatLabs/cli-memo/blob/main/docs/archive.md) ·
310
+ [import a folder on wirecat.dev](https://wirecat.dev/en/docs/memo#import-the-folder-you-choose)
315
311
 
316
- - Read only: the mailbox is opened read-only, nothing is sent, and no mail is marked read.
317
- - Run it again any time: what is stored is skipped; `--max` (default 200) bounds the new mails read
318
- per run, and the next run continues.
319
- - A mail deleted at the source loses its text in the store. The first two days of the window are left
320
- alone, and a run that finds an unusually large share missing deletes nothing and says so. Mail moved
321
- to Spam leaves All Mail and counts as deleted.
312
+ ## Configuration
322
313
 
323
- Set the account up in Himalaya first (an IMAP account with a Gmail
324
- [app password](https://myaccount.google.com/apppasswords); `bin/mail-password <name>` stores it in the
325
- keyring), then name it in `~/.config/cli-memo/config.json`:
314
+ `memo folders add` and `memo auto on` write `~/.config/cli-memo/config.json` for you. By hand you set what
315
+ to skip, mail accounts and where exported notes go:
326
316
 
327
317
  ```json
328
- { "mail": { "accounts": [{ "name": "work", "address": "you@example.com" }] } }
318
+ {
319
+ "notes": { "ignore": ["Journal/Private.md", "Archive"], "export": { "dir": "/path/to/vault/memo" } },
320
+ "mail": { "accounts": [{ "name": "work", "address": "you@example.com" }] }
321
+ }
329
322
  ```
330
323
 
331
- `mail.maxBodyChars` (default 1,000,000) and `mail.maxAttachmentChars` (default 200,000) set how many characters
332
- of a body and of one attachment's text are kept.
324
+ More: [configuration](https://github.com/WireCatLabs/cli-memo/blob/main/docs/configuration.md) ·
325
+ [configuration on wirecat.dev](https://wirecat.dev/en/docs/configuration)
333
326
 
334
- ## People
327
+ ## Security
335
328
 
336
- Who is who is decided in messaging: `tg contacts link <person> email:<address>` (or `max contacts link`)
337
- records that a messenger identity and a mail address are one person, in the shared store. A same name
338
- is never enough. `memo` only names the note that is about the person:
329
+ - Note folders and mailboxes are read-only; nothing is sent, moved or marked read.
330
+ - What memo adds — your notes, links, tags, tasks, memories — stays in the local store.
331
+ - A note or mail deleted at the source loses its text in the store on the next import; a run that finds an
332
+ unusually large share missing deletes nothing and says so.
333
+ - Evidence reaches a model only with `--model`, and a remote one only with `--allow-remote`.
334
+ - Agents propose; only you confirm memories and approve actions.
339
335
 
340
- ```sh
341
- memo note telegram:"Rin Example" ~/Notes/people/Rin.md
342
- memo note telegram:"Rin Example" --clear
343
- ```
336
+ More: [security](https://github.com/WireCatLabs/cli-memo/blob/main/docs/security.md) ·
337
+ [security on wirecat.dev](https://wirecat.dev/en/docs/security)
344
338
 
345
- An identity is `<messenger>:<name or id>`; a name two people share is refused, with their ids to
346
- choose from. The note must be imported first; the link is an `about` link in the store. Entries of an
347
- older `~/.config/cli-memo/people-notes.json` move into the store once their notes are imported; the file
348
- itself is left as it is.
339
+ ## Limits
349
340
 
350
- ## Tags on sources
341
+ - Files up to 50 MiB; stored text up to 200,000 characters a file. Scanned PDFs and legacy DOC/XLS are
342
+ reported, not read.
343
+ - Search by meaning embeds at most 600 chunks a run; the next run continues.
344
+ - `memo mail <account> import` reads 200 new messages a run by default (`--max`) and keeps up to 1,000,000
345
+ characters of a body and 200,000 of an attachment's text (`mail.maxBodyChars`, `mail.maxAttachmentChars`).
346
+ - Searches return at most 100 results; `tags list` shows 100 labels unless `--limit` says more.
347
+ - Tags are 1–32 letters a–z, digits or hyphens.
351
348
 
352
- ```sh
353
- memo tags add work follow-up --note note:NOTE_ID
354
- memo tags add project --folder FOLDER_ID --path Projects
355
- memo search notes "budget" --tag work
356
- memo tags add follow-up --message 'msg:email/you%40example.com/12345/67890'
357
- memo tags add follow-up --chat 12345 --provider email --account you@example.com
358
- memo tags list --tag follow-up --json
359
- tg search mail 'tag:follow-up'
360
- ```
349
+ More: [documents in a folder](https://github.com/WireCatLabs/cli-memo/blob/main/docs/notes.md#documents-in-a-folder) ·
350
+ [files memo can read](https://wirecat.dev/en/docs/memo#files-memo-can-read)
361
351
 
362
- A note is labelled by its reference (`--note note:<id>`, or `document:<id>` for a file in a notes
363
- folder), an email or messenger message by its full `msg:` locator, a mail thread or chat by its exact id
364
- and account. A person, organization, project or task is labelled by `--person`, `--organization`,
365
- `--project` or `--task`, with no account; a contact names its account, and so does a meeting:
366
- `--meeting <id> --provider <provider> --account <account>`, the meeting's id in the store. A note about a
367
- meeting takes the same three options: `memo notes add 'Send the agenda' --meeting <id> --provider <provider>
368
- --account <account>`. `--folder` with an id from
369
- `memo folders list`, and `--path` for one subfolder, labels every note under it at any depth. Tags use 1–32 letters a–z, digits or hyphens; case is ignored.
370
- Adding an existing tag or removing an absent one leaves it unchanged.
371
-
372
- Labels live in the shared local store. Tagging leaves note files, front matter, Gmail labels and mailbox
373
- flags untouched. Labels survive edits and moves of the note; a deleted note disappears from search.
374
- `tags list` shows up to 100 labels by default (`--limit` for more, `hasMore` in JSON); a note's tags
375
- say whether its file or you stated them. Contact identity
376
- tags remain available through `tg|max tags`.
352
+ ## When something is missing
353
+
354
+ - **Searched by words only:** the meaning model is not downloaded — `tg models text download e5-small`.
355
+ - **A folder is refused by import:** it has no id yet — `memo folders add <path>`.
356
+ - **A name is refused:** two people share it; use one of the ids it lists.
357
+ - **`memo ask` asks for a scope:** add `--all`, or `--provider` with `--account`.
358
+ - **An empty search:** the store holds nothing that matches — not proof that it never happened. Try the
359
+ kind's own search, looser words, or import that source first.
360
+
361
+ More: [if something is missing](https://wirecat.dev/en/docs/memo#if-something-is-missing) ·
362
+ [search and evidence](https://github.com/WireCatLabs/cli-memo/blob/main/docs/search.md)
363
+
364
+ ## Part of WireCat
365
+
366
+ [WireCat](https://wirecat.dev) is an open-source, local-first context layer for AI agents: tg for
367
+ Telegram, max for MAX, memo for your notes and mail, all in one local store. Start with your notes. Add
368
+ more context when you need it. Your context. Any agent.
369
+
370
+ ## Technical docs
371
+
372
+ | Page | What it covers |
373
+ | --- | --- |
374
+ | [Installation](https://github.com/WireCatLabs/cli-memo/blob/main/docs/installation.md) | Requirements, install, where files go, update |
375
+ | [Notes](https://github.com/WireCatLabs/cli-memo/blob/main/docs/notes.md) | Folders, formats, documents, your own notes, export |
376
+ | [Search and evidence](https://github.com/WireCatLabs/cli-memo/blob/main/docs/search.md) | Query language, `search all`, `ask` |
377
+ | [People, organizations and projects](https://github.com/WireCatLabs/cli-memo/blob/main/docs/people.md) | Person context, linking, relationships |
378
+ | [Mail](https://github.com/WireCatLabs/cli-memo/blob/main/docs/mail.md) | Gmail and IMAP through Himalaya |
379
+ | [Tags](https://github.com/WireCatLabs/cli-memo/blob/main/docs/tags.md) | Labels on any source |
380
+ | [Open work and reminders](https://github.com/WireCatLabs/cli-memo/blob/main/docs/tasks.md) | Tasks and local reminders |
381
+ | [Memories, facts, proposed actions and MCP](https://github.com/WireCatLabs/cli-memo/blob/main/docs/mcp.md) | What agents propose, the agent log |
382
+ | [Keeping the store current](https://github.com/WireCatLabs/cli-memo/blob/main/docs/archive.md) | `memo import` and the timer |
383
+ | [Configuration](https://github.com/WireCatLabs/cli-memo/blob/main/docs/configuration.md) | Every setting and variable |
384
+ | [Security](https://github.com/WireCatLabs/cli-memo/blob/main/docs/security.md) | What is read, written and sent |
385
+ | [Changelog](https://github.com/WireCatLabs/cli-memo/blob/main/CHANGELOG.md) | Every release |
386
+
387
+ The reader guides live on [wirecat.dev](https://wirecat.dev/en/docs/memo).
377
388
 
378
389
  ## Development
379
390
 
@@ -382,6 +393,10 @@ pnpm install
382
393
  pnpm lint && pnpm typecheck && pnpm test
383
394
  ```
384
395
 
396
+ Pull requests are welcome; examples and tests use invented people only.
397
+
398
+ More: [installation](https://github.com/WireCatLabs/cli-memo/blob/main/docs/installation.md#development)
399
+
385
400
  ## License
386
401
 
387
- [Apache License 2.0](LICENSE).
402
+ [Apache License 2.0](https://github.com/WireCatLabs/cli-memo/blob/main/LICENSE).