@cerefox/memory 1.2.1 → 1.3.0-beta.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.
package/AGENT_GUIDE.md CHANGED
@@ -15,7 +15,7 @@ It is not a message bus -- it is curated, versioned, searchable memory backed by
15
15
 
16
16
  You'll be using **one** of these — whichever your user (or the harness) has configured:
17
17
 
18
- 1. **MCP tools (default)** — ten named tools (`cerefox_search`, `cerefox_ingest`, …, `cerefox_get_help`) exposed by either a local MCP server (`@cerefox/memory` via npm, run as `cerefox mcp`) or the remote `cerefox-mcp` Edge Function. Tool names and parameters are documented in **The 10 Tools** below. This is the recommended path for purpose-built agent clients.
18
+ 1. **MCP tools (default)** — 12 named tools (`cerefox_search`, `cerefox_ingest`, …, `cerefox_get_help`) exposed by either a local MCP server (`@cerefox/memory` via npm, run as `cerefox mcp`) or the remote `cerefox-mcp` Edge Function. Tool names and parameters are documented in **The 12 Tools** below. This is the recommended path for purpose-built agent clients.
19
19
  2. **Shell CLI (Bash tool)** — the same operations exposed as a local `cerefox …` command (the TypeScript CLI from `@cerefox/memory`, resource-verb shape — e.g. `cerefox document get`, `cerefox project list`), invoked via your Bash tool. Used when your user prefers not to install/configure an MCP server. The semantics are identical; only the surface differs. See **Using Cerefox via the CLI** near the bottom of this guide for the MCP-tool → CLI-command mapping and the small list of behavioural differences.
20
20
 
21
21
  If you're not sure which mode you're in: check whether `cerefox_search` shows up in your tool list. If yes, use MCP. If no, ask your user where the Cerefox checkout lives — they'll have told you, typically in `CLAUDE.md`, `AGENTS.md`, or an equivalent project memory file.
@@ -34,7 +34,7 @@ The tool is intentionally MCP-only so an agent that has been dropped into Cerefo
34
34
 
35
35
  ---
36
36
 
37
- ## The 10 Tools
37
+ ## The 12 Tools
38
38
 
39
39
  ### cerefox_search
40
40
 
@@ -68,7 +68,7 @@ Save a new document or update an existing one.
68
68
  | `content` | Yes | Markdown content. Use H1/H2/H3 headings -- the chunker uses them for segmentation. |
69
69
  | `document_id` | No | UUID of an existing document to update. When provided, updates that document directly regardless of `update_if_exists`. Returns an error if the document does not exist. Workflow: search → note the `[id: ...]` → pass here. |
70
70
  | `update_if_exists` | No | When `true`, updates the document with the same title (versions the old content). Default `false`. Ignored when `document_id` is provided. |
71
- | `expected_content_hash` | **Yes, on content updates** | Optimistic-concurrency token: the `content_hash` of the version you based your edit on (returned by `cerefox_get_document`, `cerefox_search`, and `cerefox_metadata_search`). Stale → **conflict error** (re-read, merge, retry). Absent → **token-required error**. Not needed when creating. See "Concurrent writers" below. |
71
+ | `expected_content_hash` | **Yes, on content updates** | Optimistic-concurrency token: the `content_hash` of the version you based your edit on. **Every read AND every write returns one** — `cerefox_get_document` (including outline mode), `cerefox_search`, `cerefox_metadata_search`, and since v1.3.0 `cerefox_ingest` itself, *including on create* (#189). A document is born holding its token, so you never need to re-read something you just wrote. Stale → **conflict error** (re-read, merge, retry). Absent → **token-required error**. Not needed *as input* when creating. See "Concurrent writers" below. |
72
72
  | `last_write_wins` | No | Explicitly skip the concurrency check (default `false`). Use ONLY when an external source of truth makes conflicts meaningless (file re-sync). Recorded in the audit log. **Never use it to silence a conflict.** |
73
73
  | `project_name` | No | **Single** project name (created if absent). On update: **non-destructive add** — ensures this membership exists, preserves others. See "Project membership semantics" below. |
74
74
  | `project_names` | No | **List** of project names (each created if absent). On update: **destructive replace** — sets the document's full project set to exactly this list. Use when you want to set multiple projects at once, or deliberately change the membership list. Wins over `project_name` when both are passed. |
@@ -121,9 +121,51 @@ Retrieve the complete text of a document by its UUID.
121
121
  |-----------|----------|-------------|
122
122
  | `document_id` | Yes | UUID from search results `[id: ...]`. |
123
123
  | `version_id` | No | UUID of an archived version (from `cerefox_list_versions`). |
124
+ | `outline` | No | `true` returns the document's **structure instead of its content**: heading paths, levels, per-section sizes, plus `content_hash` and total size. Much cheaper than a full read. The paths are exactly what the edit tools take as `anchor_heading`. |
124
125
  | `requestor` | No | Your agent name. |
125
126
 
126
- Use this when search returns partial results, or to read a previous version before restoring it. The response header includes the document's current `content_hash` — pass it back as `expected_content_hash` when updating via `cerefox_ingest`.
127
+ Use this when search returns partial results, or to read a previous version before restoring it. The response header includes the document's current `content_hash` — pass it back as `expected_content_hash` when updating via `cerefox_ingest` or editing via `cerefox_insert` / `cerefox_edit`.
128
+
129
+ **Before editing a document you have not read this session, call it with `outline: true` first.** It answers the three questions an edit needs — what are the anchors, how big is each section, what is the current hash — without pulling the body into your context.
130
+
131
+ ---
132
+
133
+ ### cerefox_insert
134
+
135
+ Add text to a document **without resending it**. Purely additive: this tool cannot remove or overwrite existing content, so a mistaken call cannot destroy anything.
136
+
137
+ | Parameter | Required | Description |
138
+ |-----------|----------|-------------|
139
+ | `document_id` | Yes | UUID of the document. |
140
+ | `text` | Yes | Markdown to insert. Blank-line separation from surrounding content is handled for you. |
141
+ | `position` | Yes | `end_of_document` (plain append) · `end_of_section` (add to a section's body — the most common mid-document add) · `after_heading` (lead-in text) · `before_heading` (a new block above a section). |
142
+ | `anchor_heading` | Unless `end_of_document` | The exact heading line (`## Intake`) or a ` > ` parent path (`## Intake > ### Notes`) when a heading appears more than once. |
143
+ | `section_part` | Sometimes | Only when the target section has BOTH its own content and child sections: `own_body` (before the first child) or `subtree` (after everything nested under it). If it is needed, the error tells you and lists both options. |
144
+ | `expected_content_hash` | **Yes** | The hash of the version you are basing this on. There is **no `last_write_wins` on this tool**. |
145
+ | `requestor` | No | Your agent name. |
146
+
147
+ Returns the **new `content_hash` and size — not the document**. Chain edits by passing each response's hash into the next call.
148
+
149
+ Prefer this over re-ingesting for any addition: a decision-log entry, a bullet under a heading, a new section. Re-sending a whole document to add three paragraphs means reproducing every untouched character verbatim, and any drift silently corrupts content nobody asked you to touch.
150
+
151
+ ---
152
+
153
+ ### cerefox_edit
154
+
155
+ Change parts of a document: **one to many operations applied atomically in a single write**.
156
+
157
+ | Parameter | Required | Description |
158
+ |-----------|----------|-------------|
159
+ | `document_id` | Yes | UUID of the document. |
160
+ | `operations` | Yes | Array of operations, applied **in order, all-or-nothing**. Each is `{op, ...}` with `op` one of `insert` (same fields as `cerefox_insert`), `replace_section` (`anchor_heading`, `text`; swaps the body, keeps the heading), `delete_section` (`anchor_heading`, optional `scope`: `body_only` default keeps the heading, `heading_and_body` removes it too). |
161
+ | `expected_content_hash` | **Yes** | One token for the whole call. No `last_write_wins`. |
162
+ | `requestor` | No | Your agent name. |
163
+
164
+ **Put changes that belong together in ONE call.** Operations apply in order against the evolving document (op 2 sees op 1's result), and a half-applied state is impossible — so a table row and the running total it feeds cannot end up disagreeing. If any operation fails (bad anchor, ambiguity), nothing at all is written and the error names the failing operation.
165
+
166
+ **To change a single line**, `replace_section` on its smallest enclosing heading and resend just that section. That is the intended granularity — line-level anchors were deliberately excluded because they silently edit the wrong place.
167
+
168
+ The audit trail records each operation distinctly (`insert` / `replace-section` / `delete-section`), so *added to*, *rewrote* and *removed* stay distinguishable from a full rewrite.
127
169
 
128
170
  ---
129
171
 
@@ -275,7 +317,27 @@ Metadata is matched as **strings**, so store the flag as the string `"true"` (no
275
317
 
276
318
  ## Key Workflows
277
319
 
278
- ### Search then update (ID-based -- preferred)
320
+ ### Add to or change part of a document (preferred over re-sending)
321
+
322
+ ```
323
+ 1. cerefox_get_document(id, outline=true) -- anchors + sizes + content_hash,
324
+ no body in your context
325
+ 2a. Adding? cerefox_insert(id, text, position, anchor_heading?,
326
+ expected_content_hash)
327
+ 2b. Changing? cerefox_edit(id, operations=[...], expected_content_hash)
328
+ -- put coordinated changes in ONE call; they apply atomically
329
+ 3. Each response returns the NEW content_hash — chain further edits with it.
330
+ On a conflict: re-read (outline is enough to re-anchor), decide whether your
331
+ edit still applies, retry with the current hash. These tools cannot overwrite
332
+ a concurrent writer's work.
333
+ ```
334
+
335
+ Re-send the full document (the workflows below) only when the change genuinely
336
+ spans most of it — a restructure, a rewrite. For anything less, partial edits
337
+ remove the transcription risk entirely: you never reproduce content you are not
338
+ changing.
339
+
340
+ ### Search then update (ID-based -- preferred for full rewrites)
279
341
 
280
342
  ```
281
343
  1. cerefox_search("topic") -- find relevant docs, note [id: uuid]
@@ -1,6 +1,6 @@
1
1
  # Cerefox Knowledge Base -- Agent Quick Reference
2
2
 
3
- Cerefox is a persistent, shared knowledge base. You have **14 MCP tools** (13 of them have CLI equivalents — `cerefox_get_help` is MCP-only). For the full guide, search Cerefox for "How AI Agents Use Cerefox" or call `cerefox_get_help` to retrieve this content over MCP.
3
+ Cerefox is a persistent, shared knowledge base. You have **16 MCP tools** (15 of them have CLI equivalents — `cerefox_get_help` is MCP-only). For the full guide, search Cerefox for "How AI Agents Use Cerefox" or call `cerefox_get_help` to retrieve this content over MCP.
4
4
 
5
5
  ## Tools
6
6
 
@@ -8,7 +8,9 @@ Cerefox is a persistent, shared knowledge base. You have **14 MCP tools** (13 of
8
8
  |------|---------|------------|
9
9
  | `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |
10
10
  | `cerefox_ingest` | Save or update a document | `title`, `content` (required), `document_id` (update by ID), `expected_content_hash` (**required on content updates** — see rule 9), `last_write_wins`, `update_if_exists`, `project_name` (single, non-destructive add on update), `project_names` (list, destructive replace on update), `metadata` (omit on update to keep existing tags; `{}` clears), `author` |
11
- | `cerefox_get_document` | Get full document by ID (header includes `content_hash` the update token) | `document_id` (required) |
11
+ | `cerefox_insert` | **Add** to a document without resending it. Cannot destroy content. | `document_id`, `text`, `position` (`end_of_document`/`end_of_section`/`after_heading`/`before_heading`), `expected_content_hash` (required), `anchor_heading` (unless `end_of_document`), `section_part` |
12
+ | `cerefox_edit` | **Change** parts of a document: 1..n operations applied atomically | `document_id`, `operations` (`insert`/`replace_section`/`delete_section`), `expected_content_hash` (required) |
13
+ | `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token), or with `outline: true` just its heading paths, sizes and hash | `document_id` (required), `outline` |
12
14
  | `cerefox_list_versions` | Version history of a document | `document_id` (required) |
13
15
  | `cerefox_set_relation` ⚑ | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |
14
16
  | `cerefox_delete_relation` ⚑ | Remove a relation | `source_id`, `target_id`, `rel_type` |
@@ -26,6 +28,33 @@ operator enables them (`relations_enabled`). **Trust your own tool list**: if
26
28
  they are not in it, the feature is switched off for this deployment. That is
27
29
  normal, not an error, and not something to work around.
28
30
 
31
+ ## Editing part of a document (prefer this over re-sending)
32
+
33
+ **Re-sending a whole document to change part of it is the main way agents lose
34
+ data.** You have to reproduce the untouched remainder verbatim, and any drift
35
+ silently rewrites content nobody asked you to touch — which the caller cannot
36
+ diff. Use the partial-edit tools instead:
37
+
38
+ 1. **Learn the anchors** — `cerefox_get_document(document_id, outline: true)`.
39
+ Returns heading paths, per-section sizes and the `content_hash`, without the
40
+ body. The paths it returns are exactly what `anchor_heading` accepts.
41
+ 2. **Add** → `cerefox_insert`. `end_of_document` is a plain append;
42
+ `end_of_section` adds inside a named section. It is structurally incapable of
43
+ removing anything, so "I meant to append" cannot become "I replaced the file".
44
+ 3. **Change or remove** → `cerefox_edit`. Put changes that belong together in
45
+ ONE call: they apply atomically, so a table row and the total it feeds cannot
46
+ end up disagreeing. To change a single line, `replace_section` on its
47
+ smallest enclosing heading — that is the intended granularity, not a
48
+ workaround.
49
+ 4. Both require `expected_content_hash` and **have no last-write-wins**. A
50
+ conflict means someone else changed the document; re-read and decide, do not
51
+ force it.
52
+
53
+ **When an anchor is ambiguous the tool refuses and hands you the options** — a
54
+ repeated heading returns the qualifying paths, and a section with both its own
55
+ content and sub-sections returns both `section_part` choices. That is a
56
+ recoverable answer, not a failure: retry with what it gave you.
57
+
29
58
  ## Essential Rules
30
59
 
31
60
  1. **Search before ingesting** -- check if the document exists first.
@@ -36,7 +65,7 @@ normal, not an error, and not something to work around.
36
65
  6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.
37
66
  7. **Deletes are soft (recoverable); purge is web-UI-only.** If you decide to delete, surface it to the user (`I soft-deleted X — recoverable from the Cerefox web UI trash`). You cannot un-do your own delete from agent code by design.
38
67
  8. **Cross-doc links inside content**: **always use `[Text](document-uuid)`.** UUIDs are the only fully reliable link form — stable across title changes, never ambiguous, no encoding gotchas. Every `cerefox_search` result shows `[id: <uuid>]` after the title; grab it and use it. Title-based linking (`[Text](<Title With Spaces>)`) is fragile (breaks on colons, parens, ampersands, brackets — silently navigates to wrong page) — **don't write title-based links**; do an extra search to get the UUID instead. Repo-path forms (`[Text](docs/path.md)`) exist for repo-ingested files; don't construct manually. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.
39
- 9. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you read (shown by `cerefox_get_document`, `cerefox_search`, and `cerefox_metadata_search`) when updating a document. If it's stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer's work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict.
68
+ 9. **Concurrency: content updates require `expected_content_hash`.** Pass the `content_hash` you last saw — every read shows one (`cerefox_get_document` incl. outline mode, `cerefox_search`, `cerefox_metadata_search`) and **every write returns the new one, including create** (v1.3.0, #189), so after writing you already hold the token for your next edit; no re-read needed. If it's stale you get a **conflict** — re-read the document, merge your changes into the latest content, retry with the new hash. **Never resolve a conflict by overwriting blindly** — the current content includes another writer's work. `last_write_wins: true` skips the check; use it ONLY when an external source of truth makes conflicts meaningless (file re-sync), never to silence a conflict.
40
69
  10. **Search: prefer a few distinctive terms; heed `below confidence`.** When nothing clears the relevance threshold, `cerefox_search` returns the closest candidates prefixed with a `below confidence` warning instead of an empty set — that flag means **weak signal, not absent knowledge**: check the candidates' scores and titles before concluding the KB lacks the content. A truly empty response means nothing even weakly related exists.
41
70
  11. **Relations express how documents relate; lifecycle tells you if knowledge is still good.** Use `cerefox_set_relation` when one document supersedes, contradicts, references, or continues another. `supersedes` marks the target **superseded**; `contradicts` marks **both** stale; `related_to`/`duplicates`/`contradicts` are symmetric (both directions written). Any other type string is accepted without special behaviour. When a search result or `cerefox_get_relations` shows a neighbour marked `[superseded]` or `[stale]`, say so rather than presenting it as current.
42
71
  12. **Project memberships — non-destructive by default**: on `cerefox_ingest` updates, **`project_name` (singular) is a non-destructive add** (ensures membership, preserves others). Use **`project_names` (list)** when you want to set the doc's full project set in one call (destructive replace). For metadata-only project changes without writing content, use **`cerefox_set_document_projects(document_id, project_names)`** — that tool is the destructive-replace contract made explicit. Never call `cerefox_set_document_projects` with a single name when you mean "add" — that would REMOVE the doc from all other projects. When in doubt, use `cerefox_ingest` with singular `project_name`.
package/README.md CHANGED
@@ -29,7 +29,7 @@ This package contains a single binary, **`cerefox`**:
29
29
  | Subcommand | What it does |
30
30
  |---|---|
31
31
  | `cerefox <command>` | CLI — search, ingest, list, version-history, audit-log, lifecycle (`init`, `doctor`, `configure-agent`, `self-update`). Callable from any directory. |
32
- | `cerefox mcp` | Local stdio MCP server. Drop-in for Claude Code, Cursor, Claude Desktop, Codex CLI, Gemini CLI. Exposes the same 10 MCP tools as the remote `cerefox-mcp` Edge Function. |
32
+ | `cerefox mcp` | Local stdio MCP server. Drop-in for Claude Code, Cursor, Claude Desktop, Codex CLI, Gemini CLI. Exposes the same 12 core MCP tools as the remote `cerefox-mcp` Edge Function, plus 4 document-relation tools that stay hidden until enabled. |
33
33
  | `cerefox web` | Local web app at `http://localhost:8000` — React UI for browsing, searching, editing, and ingesting documents. Backed by an in-process Hono server that exposes the same `/api/v1/*` REST surface as the bundled Edge Functions. |
34
34
 
35
35
  > **What this package isn't:** the source of truth for Cerefox's architecture
@@ -148,11 +148,21 @@ For manual configuration (any other MCP client), the canonical entry is:
148
148
  ```
149
149
 
150
150
  Once configured, any of these clients can search + write your Cerefox KB via
151
- the 10 MCP tools (`cerefox_search`, `cerefox_ingest`, `cerefox_get_document`,
152
- `cerefox_list_versions`, `cerefox_list_projects`, `cerefox_list_metadata_keys`,
151
+ the 12 core MCP tools (`cerefox_search`, `cerefox_ingest`, `cerefox_insert`,
152
+ `cerefox_edit`, `cerefox_get_document`, `cerefox_list_versions`,
153
+ `cerefox_list_projects`, `cerefox_list_metadata_keys`,
153
154
  `cerefox_metadata_search`, `cerefox_set_document_projects`,
154
155
  `cerefox_get_audit_log`, `cerefox_get_help`).
155
156
 
157
+ `cerefox_insert` and `cerefox_edit` change part of a document without resending
158
+ it — the agent sends what changed and the server assembles the result.
159
+
160
+ Four more tools (`cerefox_set_relation`, `cerefox_delete_relation`,
161
+ `cerefox_get_relations`, `cerefox_get_neighbors`) build a typed graph between
162
+ documents. They ship **dormant**: hidden from every agent until you opt in with
163
+ `cerefox config set relations_enabled true`. Toggling changes visibility only,
164
+ never your data.
165
+
156
166
  ---
157
167
 
158
168
  ## Common commands