@cerefox/memory 1.6.1 → 1.7.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.
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)** — 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 13 Tools** below. This is the recommended path for purpose-built agent clients.
18
+ 1. **MCP tools (default)** — 15 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 15 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 13 Tools
37
+ ## The 15 Tools
38
38
 
39
39
  ### cerefox_search
40
40
 
@@ -191,6 +191,41 @@ The audit trail records each operation distinctly (`insert` / `replace-section`
191
191
 
192
192
  ---
193
193
 
194
+ ### cerefox_delete_document
195
+
196
+ **Soft**-delete a document: it leaves search results and lands in the web-UI trash, recoverable until a human purges it. New in v1.7.0 (#208) — before that, deletion was CLI/web-UI-only and agents had to ask their user.
197
+
198
+ | Parameter | Required | Description |
199
+ |-----------|----------|-------------|
200
+ | `document_id` | Yes | UUID of the document to soft-delete. |
201
+ | `expected_content_hash` | **Yes** | The `content_hash` of the document **as you read it**. A delete must follow a read: if you have not read the document, read it first. A stale hash fails with a conflict — re-read, reconsider, retry. There is deliberately no `last_write_wins`. |
202
+ | `reason` | No | Why the document is being deleted. Recorded in the audit-log entry — it is the main thing the human reviewing the trash has to go on. Short and specific. |
203
+ | `author` / `requestor` | No | Your agent name (audit / usage log). |
204
+
205
+ **The hash requirement is the point, not a formality.** The CLI's delete asks a human "Continue? y/N"; an agent has no prompt, so its proof-of-intent is evidence that it read what it is deleting. If the document changed between your read and your delete, the conflict is information: someone wrote to a document you were about to discard — look before deciding again.
206
+
207
+ **A mistaken delete can be undone with `cerefox_restore_document`** (below). Permanent purge is web-UI-only (human-in-the-loop, see **Governance**). Deleting an already-deleted document is a reported no-op — the original deletion time stands and no duplicate audit entry is written — but the hash is still validated first: the read-proof holds in the trash too. A trashed document also refuses content updates (`cerefox_ingest` errors; restore first), so what you review in the trash is what a restore brings back.
208
+
209
+ **Always tell your user what you deleted and why.** They review the trash; your `reason` and your report are what make that review possible.
210
+
211
+ ---
212
+
213
+ ### cerefox_restore_document
214
+
215
+ Restore a soft-deleted document from the trash — the audited inverse of `cerefox_delete_document`. New in v1.7.0 (#210), by maintainer decision: every restore carries author attribution in the audit log, restoring cannot destroy content, and it keeps parity with the CLI's `document restore`.
216
+
217
+ | Parameter | Required | Description |
218
+ |-----------|----------|-------------|
219
+ | `document_id` | Yes | UUID of the soft-deleted document. |
220
+ | `reason` | No | Why it is being restored. Recorded in the audit-log entry. |
221
+ | `author` / `requestor` | No | Your agent name (audit / usage log). |
222
+
223
+ No `expected_content_hash`: a trashed document cannot be concurrently edited, so there is no read-freshness to prove. Restoring a document that is not deleted is a reported no-op. **Purge remains the one action with no agent surface** — once a human purges from the web UI, the document is gone and cannot be restored.
224
+
225
+ **Tell your user about restores just as you do deletes** — both are lifecycle changes they should be able to follow in the audit trail and in your report.
226
+
227
+ ---
228
+
194
229
  ### cerefox_list_versions
195
230
 
196
231
  Show version history of a document.
@@ -251,6 +286,21 @@ Call once per session to discover available projects before filtering search res
251
286
 
252
287
  ---
253
288
 
289
+ ### cerefox_set_document_metadata
290
+
291
+ Change a document's metadata (tags) **without resending its content** (v1.6.0, #204). Merges by default, so concurrent agents setting different keys cannot clobber each other.
292
+
293
+ | Parameter | Required | Description |
294
+ |-----------|----------|-------------|
295
+ | `document_id` | Yes | UUID of the document to tag. |
296
+ | `metadata` | Yes | Keys to set. Values are JSON strings by convention (a `metadata_filter` matches JSONB as strings). A `null` value REMOVES that key. Keys you do not mention are left alone unless `replace` is true. |
297
+ | `replace` | No | Set the metadata to EXACTLY this object, discarding any key not listed. Rare — the same destructive contract as `cerefox_set_document_projects`. |
298
+ | `author` / `requestor` | No | Your agent name (audit / usage log). |
299
+
300
+ Content, chunks and embeddings are untouched; no new version is created. The response reports what *changed* (keys set / removed), not what was asked for. Use this instead of `cerefox_ingest` whenever only the tags are changing.
301
+
302
+ ---
303
+
254
304
  ### cerefox_set_document_projects
255
305
 
256
306
  Set the document's project memberships to EXACTLY the given list. **Destructive replace.** Any existing memberships not in the list are removed. Content is untouched. Logged as `update-metadata` in the audit log.
@@ -438,6 +488,27 @@ Documents you ingest may contain markdown links to other Cerefox documents. The
438
488
  [Opportunity Index](c937b70f-77af-43d3-b9bc-9f31e0d2041d)
439
489
  ```
440
490
 
491
+ **The server validates these links on every write (v1.7.0, #214).** A write
492
+ whose content contains a `[Text](uuid)` link to a document id that does not
493
+ exist is **rejected**, listing the offending id(s). This exists because
494
+ long random ids are a worst-case input for regenerating text — a mangled
495
+ UUID silently becomes a dead link, and the guard turns that into a loud,
496
+ same-turn-fixable error. Three things to know:
497
+
498
+ - **Do not retry unchanged.** Re-read the source you copied each link from,
499
+ correct the id(s), and resend. The error is deterministic.
500
+ - **Examples go in code formatting.** A backticked `` `[Text](uuid)` `` or a
501
+ fenced block is not a link and is not validated — that is the escape
502
+ mechanism, and it is just correct markdown authoring.
503
+ - **Only links your write introduces are validated on updates.** A dead
504
+ link the document already carried (its target purged after linking) does
505
+ not block your unrelated edit — legacy dead links are found by the
506
+ dead-link sweep (#214 phase 2), not by holding your edit hostage. New
507
+ documents validate every link.
508
+
509
+ `[[Wikilinks]]` are NOT validated — they remain the sanctioned form for
510
+ "flag a document to create later."
511
+
441
512
  UUIDs are the only link form that is fully reliable:
442
513
 
443
514
  - **Stable**: survives title changes. If the target gets renamed, the link still resolves.
@@ -493,8 +564,8 @@ If you're using Cerefox via the local CLI (Path C from `connect-agents.md`), the
493
564
  ## Governance
494
565
 
495
566
  - **Review status**: agent writes set `pending_review`; human edits set `approved`. Both are searchable.
496
- - **Soft delete**: deleted documents go to trash (recoverable). They are excluded from search. There is no delete MCP toolsoft-delete is done via the CLI (`cerefox document delete --yes --author <you> --author-type agent`) or the web UI.
497
- - **Permanent purge and restore-from-trash are web-UI-only**, by design. If you decide to delete something, **tell the user explicitly** that you soft-deleted it and that they can review or restore it via the Cerefox web UI. You cannot un-do your own soft-delete from agent code; only the human can. See [`docs/guides/access-paths.md` → Destructive operations and the trust model](docs/guides/access-paths.md#destructive-operations-and-the-trust-model).
567
+ - **Soft delete**: deleted documents go to trash (recoverable). They are excluded from search. Delete via `cerefox_delete_document` (MCP, v1.7.0+requires the document's `content_hash` as you read it), the CLI (`cerefox document delete --yes --author <you> --author-type agent`), or the web UI.
568
+ - **Restore is agent-reachable; permanent purge is web-UI-only.** A mistaken soft-delete can be undone with `cerefox_restore_document` (or `cerefox document restore`), fully audited (#210, v1.7.0). Purge the only action that actually destroys data keeps its human-in-the-loop confirmation in the web UI. If you delete or restore something, **tell the user explicitly** so they can follow it in the audit trail. See [`docs/guides/access-paths.md` → Destructive operations and the trust model](docs/guides/access-paths.md#destructive-operations-and-the-trust-model).
498
569
  - **Versioning**: every update via `update_if_exists` creates an archived version. Old content is always recoverable.
499
570
  - **Audit log**: all write operations are recorded with author, timestamp, and size changes.
500
571
 
@@ -524,12 +595,15 @@ The Python implementation was fully removed at v1.0.0; every command is the Type
524
595
  | `cerefox_get_document(document_id, version_id, requestor)` | `cerefox document get <document-id> --version-id <vid> --requestor <name>` |
525
596
  | `cerefox_list_versions(document_id, requestor)` | `cerefox document version list <document-id> --requestor <name>` |
526
597
  | `cerefox_list_projects(requestor)` | `cerefox project list --requestor <name>` |
598
+ | `cerefox_set_document_metadata(document_id, metadata, replace, author)` | `cerefox document set-metadata <document-id> --set key=value` (also `--remove key`, `--json '{...}'`, `--replace`) |
527
599
  | `cerefox_set_document_projects(document_id, project_names, author)` | `cerefox document set-projects <document-id> <name...> --author <a> --author-type user\|agent` (or `--clear` to remove all) |
528
600
  | `cerefox_list_metadata_keys()` | `cerefox metadata keys` |
529
601
  | `cerefox_metadata_search(metadata_filter, project_name, updated_since, created_since, limit, include_content, requestor)` | `cerefox metadata search --metadata-filter '<json>' --project-name <n> --updated-since <iso> --created-since <iso> --limit N --include-content --requestor <name>` |
530
602
  | `cerefox_get_audit_log(document_id, author, operation, since, until, limit, requestor)` | `cerefox audit list --document-id <id> --author <a> --operation <op> --since <iso> --until <iso> --limit N --json --requestor <name>` |
603
+ | `cerefox_delete_document(document_id, expected_content_hash, reason, author, requestor)` | `cerefox document delete <document-id> --reason <text> --author <a> --author-type user\|agent --yes` (the CLI confirms interactively instead of requiring the hash) |
604
+ | `cerefox_restore_document(document_id, reason, author, requestor)` | `cerefox document restore <document-id> --reason <text> --author <a> --author-type user\|agent` |
531
605
 
532
- > Other CLI verbs with no MCP equivalent: `cerefox document edit` (title/metadata patch), `cerefox document delete` / `cerefox document restore`, `cerefox project create` / `cerefox project edit`, `cerefox config list/get/set`, `cerefox server reindex`, `cerefox guides list/show`.
606
+ > Other CLI verbs with no MCP equivalent: `cerefox document edit` (title/metadata patch), `cerefox project create` / `cerefox project edit`, `cerefox config list/get/set`, `cerefox server reindex`, `cerefox guides list/show`.
533
607
 
534
608
  ### Caller-identity flags (set these the same way you would on MCP)
535
609
 
@@ -1,6 +1,6 @@
1
1
  # Cerefox Knowledge Base -- Agent Quick Reference
2
2
 
3
- Cerefox is a persistent, shared knowledge base. You have **17 MCP tools** (16 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 **19 MCP tools** (18 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
 
@@ -10,6 +10,8 @@ Cerefox is a persistent, shared knowledge base. You have **17 MCP tools** (16 of
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
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
12
  | `cerefox_edit` | **Change** parts of a document: 1..n operations applied atomically | `document_id`, `operations` (`insert`/`replace_section`/`delete_section`/`rename_section`), `expected_content_hash` (required) |
13
+ | `cerefox_delete_document` | **Soft**-delete a document (to trash; excluded from search; permanent purge is human-only) | `document_id`, `expected_content_hash` (**required** — a delete must follow a read), `reason` (recorded in the audit log — give one), `author` |
14
+ | `cerefox_restore_document` | Restore a soft-deleted document from the trash (audited inverse of delete; no-op if not deleted) | `document_id` (required), `reason` (recorded in the audit log), `author` |
13
15
  | `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, or with `section: "## Heading"` one section's text | `document_id` (required), `outline`, `section`, `section_part` |
14
16
  | `cerefox_list_versions` | Version history of a document | `document_id` (required) |
15
17
  | `cerefox_set_relation` ⚑ | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |
@@ -76,8 +78,8 @@ recoverable answer, not a failure: retry with what it gave you.
76
78
  4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.
77
79
  5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").
78
80
  6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.
79
- 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.
80
- 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.
81
+ 7. **Deletes are soft (recoverable); permanent purge is web-UI-only.** `cerefox_delete_document` requires the document's `content_hash` as you read it (read before you delete) and takes a `reason` — give one; it is what the human reviewing the trash sees. `cerefox_restore_document` undoes a mistaken delete (also audited, also takes a `reason`). Always surface deletes AND restores to the user. Once a human purges from the web UI, the document is gone for good.
82
+ 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. **The server validates `](uuid)` links on every write** (v1.7.0): a link to a nonexistent id rejects the write, naming the offender — that means you mangled the UUID; re-read the source and correct it, do not retry unchanged. Example ids go in backticks (code is not validated). `[[Wikilinks]]` may dangle. See `AGENT_GUIDE.md → Writing linkable content` for the full rule.
81
83
  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.
82
84
  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.
83
85
  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.
@@ -122,10 +124,10 @@ Same operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/g
122
124
  | `cerefox_list_versions` | `cerefox document version list <id> --requestor "<your-name>"` |
123
125
  | `cerefox_list_projects` | `cerefox project list --requestor "<your-name>"` |
124
126
  | `cerefox_list_metadata_keys` | `cerefox metadata keys` |
125
- | `cerefox_set_relation` | Link two documents (`source --rel_type--> target`) | `source_id`, `target_id`, `rel_type` (required), `metadata`, `author` |
126
- | `cerefox_delete_relation` | Remove a relation | `source_id`, `target_id`, `rel_type` |
127
- | `cerefox_get_relations` | All relations touching a document, both directions | `document_id` |
128
- | `cerefox_get_neighbors` | Walk the graph along ONE relation type | `document_id`, `rel_type` (required), `depth`, `from_time`, `to_time`, `limit` |
127
+ | `cerefox_insert` | `cerefox document insert <id> -t "<text>" -p <position> -a "<anchor-heading>" -e "<hash>" --requestor "<your-name>" --author-type agent` |
128
+ | `cerefox_edit` | `cerefox document edit-parts <id> --operations '<json>' -e "<hash>" --requestor "<your-name>" --author-type agent` |
129
+ | `cerefox_delete_document` | `cerefox document delete <id> --reason "<why>" --author "<your-name>" --author-type agent --yes` (confirms interactively instead of requiring the hash) |
130
+ | `cerefox_restore_document` | `cerefox document restore <id> --reason "<why>" --author "<your-name>" --author-type agent` |
129
131
  | `cerefox_metadata_search` | `cerefox metadata search --metadata-filter '<json>' --requestor "<your-name>"` (list a project: `cerefox document list --project <name>`) |
130
132
  | `cerefox_set_document_metadata` | `cerefox document set-metadata <id> --set key=value` (also `--remove key`, `--json '{...}'`, `--replace`) |
131
133
  | `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author "<your-name>" --author-type agent` (or `--clear` to remove all) |
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 13 core MCP tools as the remote `cerefox-mcp` Edge Function, plus 4 document-relation tools that stay hidden until enabled. |
32
+ | `cerefox mcp` | Local stdio MCP server. Drop-in for Claude Code, Cursor, Claude Desktop, Codex CLI, Gemini CLI. Exposes the same 15 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,8 +148,10 @@ 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 13 core MCP tools (`cerefox_search`, `cerefox_ingest`, `cerefox_insert`,
152
- `cerefox_edit`, `cerefox_get_document`, `cerefox_list_versions`,
151
+ the 15 core MCP tools (`cerefox_search`, `cerefox_ingest`, `cerefox_insert`,
152
+ `cerefox_edit`, `cerefox_delete_document`, `cerefox_restore_document`,
153
+ `cerefox_get_document`,
154
+ `cerefox_list_versions`,
153
155
  `cerefox_list_projects`, `cerefox_list_metadata_keys`,
154
156
  `cerefox_metadata_search`, `cerefox_set_document_projects`,
155
157
  `cerefox_set_document_metadata`,