@cerefox/memory 0.11.0 → 0.11.1
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 +1 -1
- package/AGENT_QUICK_REFERENCE.md +1 -1
- package/dist/bin/cerefox.js +14 -14
- package/dist/server-assets/_shared/ef-meta/index.ts +1 -1
- package/dist/server-assets/_shared/mcp-tools/get-help-content.ts +2 -2
- package/dist/server-assets/_shared/mcp-tools/ingest.ts +4 -1
- package/dist/server-assets/db/rpcs.sql +13 -6
- package/dist/server-assets/db/schema.sql +1 -1
- package/dist/server-assets/supabase/functions/cerefox-ingest/index.ts +7 -2
- package/docs/guides/cli.md +3 -3
- package/docs/guides/connect-agents.md +5 -1
- package/package.json +1 -1
package/AGENT_GUIDE.md
CHANGED
|
@@ -72,7 +72,7 @@ Save a new document or update an existing one.
|
|
|
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. |
|
|
75
|
-
| `metadata` | No | Arbitrary JSON. Use at minimum: `type` and `status`. |
|
|
75
|
+
| `metadata` | No | Arbitrary JSON. Use at minimum: `type` and `status`. **On update, omitting this keeps the document's existing metadata** (v0.11.1); pass `{}` to deliberately clear all tags. |
|
|
76
76
|
| `author` | No | Your agent name for audit attribution. Always set this. |
|
|
77
77
|
| `source` | No | Origin label (default "agent"). |
|
|
78
78
|
|
package/AGENT_QUICK_REFERENCE.md
CHANGED
|
@@ -7,7 +7,7 @@ Cerefox is a persistent, shared knowledge base. You have **10 MCP tools** (9 of
|
|
|
7
7
|
| Tool | Purpose | Key params |
|
|
8
8
|
|------|---------|------------|
|
|
9
9
|
| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |
|
|
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
|
|
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_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |
|
|
12
12
|
| `cerefox_list_versions` | Version history of a document | `document_id` (required) |
|
|
13
13
|
| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project's docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |
|
package/dist/bin/cerefox.js
CHANGED
|
@@ -7184,7 +7184,7 @@ var exports_meta = {};
|
|
|
7184
7184
|
__export(exports_meta, {
|
|
7185
7185
|
PKG_VERSION: () => PKG_VERSION
|
|
7186
7186
|
});
|
|
7187
|
-
var PKG_VERSION = "0.11.
|
|
7187
|
+
var PKG_VERSION = "0.11.1";
|
|
7188
7188
|
var init_meta = () => {};
|
|
7189
7189
|
|
|
7190
7190
|
// ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
|
|
@@ -54039,10 +54039,10 @@ var init_get_document = __esm(() => {
|
|
|
54039
54039
|
});
|
|
54040
54040
|
|
|
54041
54041
|
// ../../_shared/mcp-tools/get-help-content.ts
|
|
54042
|
-
var HELP_FULL = '# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **10 MCP tools** (9 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.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `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
|
|
54042
|
+
var HELP_FULL = '# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **10 MCP tools** (9 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.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `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` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project\'s docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc\'s project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., "Claude Code", "archiver"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **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.\n8. **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.\n9. **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.\n10. **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`.\n\n## Update Workflow (ID-based -- preferred)\n\n```\nsearch("topic") -> find doc [id: abc123] -> get_document(abc123) -> note its content_hash -> modify ->\ningest(title="Same Title", content="...", document_id="abc123",\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\nOn a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.\n\n## Update Workflow (title-based -- fallback)\n\n```\nsearch("topic") -> find doc (note its hash) -> modify ->\ningest(title="Same Title", content="...", update_if_exists=true,\n expected_content_hash="<the hash you read>", author="my-agent")\n```\n\n## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={"type": "decision-log"}, updated_since="2026-03-28T00:00:00Z")\n```\n\n## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …). The legacy Python `uv run cerefox` is now a frozen husk as of v0.9 — only `uv run cerefox mcp` still works.\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); common flags also have single-letter short forms (`-f`, `-p`, `-c`, `-m`, `-u`, `-a`, `-r`). Use the canonical long name (what `--help` shows) or its short form — there are no long-form aliases like `--filter` or `--count`.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search "<q>" --requestor "<your-name>"` |\n| `cerefox_ingest` (paste) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --author "<your-name>" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf \'...\' \\| cerefox document ingest --paste --title "<t>" --document-id "<uuid>" --expected-content-hash "<hash>" --author "<your-name>" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --requestor "<your-name>"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --requestor "<your-name>"` |\n| `cerefox_list_projects` | `cerefox project list --requestor "<your-name>"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter \'<json>\' --requestor "<your-name>"` (list a project: `cerefox document list --project <name>`) |\n| `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author "<your-name>" --author-type agent` (or `--clear` to remove all) |\n| `cerefox_get_audit_log` | `cerefox audit list --requestor "<your-name>"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author "<your-name>" --author-type agent`\n- Reads: `--requestor "<your-name>"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.\n', HELP_SECTIONS, HELP_SECTION_HEADINGS;
|
|
54043
54043
|
var init_get_help_content = __esm(() => {
|
|
54044
54044
|
HELP_SECTIONS = {
|
|
54045
|
-
Tools: "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `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
|
|
54045
|
+
Tools: "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `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` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project's docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc's project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |",
|
|
54046
54046
|
"Essential Rules": '## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., "Claude Code", "archiver"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user\'s `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` ("decision-log", "research", "design-doc") and `status` ("active", "draft").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **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.\n8. **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.\n9. **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.\n10. **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`.',
|
|
54047
54047
|
"Update Workflow (ID-based -- preferred)": `## Update Workflow (ID-based -- preferred)
|
|
54048
54048
|
|
|
@@ -54297,7 +54297,7 @@ async function handler4(supabase, args, ctx) {
|
|
|
54297
54297
|
const project_name = args.project_name;
|
|
54298
54298
|
const project_names_raw = args.project_names;
|
|
54299
54299
|
const source = args.source ?? "agent";
|
|
54300
|
-
const metadata = args.metadata ??
|
|
54300
|
+
const metadata = args.metadata ?? null;
|
|
54301
54301
|
const update_if_exists = args.update_if_exists ?? false;
|
|
54302
54302
|
const author = args.author ?? "mcp-agent";
|
|
54303
54303
|
const author_type = "agent";
|
|
@@ -74097,7 +74097,7 @@ import { homedir as homedir5 } from "node:os";
|
|
|
74097
74097
|
import { join as join8 } from "node:path";
|
|
74098
74098
|
|
|
74099
74099
|
// ../../_shared/ef-meta/index.ts
|
|
74100
|
-
var EF_VERSION = "0.11.
|
|
74100
|
+
var EF_VERSION = "0.11.1";
|
|
74101
74101
|
|
|
74102
74102
|
// src/cli/util/checks.ts
|
|
74103
74103
|
init_config();
|
|
@@ -75635,7 +75635,7 @@ async function action18(path, options) {
|
|
|
75635
75635
|
if (author === "unknown") {
|
|
75636
75636
|
warn("No --author / CEREFOX_AUTHOR_NAME set — audit log will record this write as 'unknown'.");
|
|
75637
75637
|
}
|
|
75638
|
-
const metadata = parseJsonObjectArg(options.metadata, "--metadata")
|
|
75638
|
+
const metadata = parseJsonObjectArg(options.metadata, "--metadata");
|
|
75639
75639
|
let projectNames;
|
|
75640
75640
|
if (options.projectNames) {
|
|
75641
75641
|
projectNames = options.projectNames.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
@@ -75662,7 +75662,7 @@ async function action18(path, options) {
|
|
|
75662
75662
|
source: options.source ?? "cli",
|
|
75663
75663
|
projectName: options.projectName ?? null,
|
|
75664
75664
|
projectNames: projectNames ?? null,
|
|
75665
|
-
metadata,
|
|
75665
|
+
metadata: metadata ?? null,
|
|
75666
75666
|
updateExisting: Boolean(options.updateIfExists),
|
|
75667
75667
|
documentId: options.documentId ?? null,
|
|
75668
75668
|
author,
|
|
@@ -75675,7 +75675,7 @@ async function action18(path, options) {
|
|
|
75675
75675
|
source: options.source ?? "cli",
|
|
75676
75676
|
projectName: options.projectName ?? null,
|
|
75677
75677
|
projectNames: projectNames ?? null,
|
|
75678
|
-
metadata,
|
|
75678
|
+
metadata: metadata ?? null,
|
|
75679
75679
|
updateExisting: Boolean(options.updateIfExists),
|
|
75680
75680
|
documentId: options.documentId ?? null,
|
|
75681
75681
|
author,
|
|
@@ -75748,7 +75748,7 @@ async function action19(dir, options) {
|
|
|
75748
75748
|
if (author === "unknown") {
|
|
75749
75749
|
warn("No --author / CEREFOX_AUTHOR_NAME set — audit log will record these writes as 'unknown'.");
|
|
75750
75750
|
}
|
|
75751
|
-
const metadata = parseJsonObjectArg(options.metadata, "--metadata")
|
|
75751
|
+
const metadata = parseJsonObjectArg(options.metadata, "--metadata");
|
|
75752
75752
|
const settings = loadSettings();
|
|
75753
75753
|
if (!settings.supabaseUrl || !settings.supabaseKey) {
|
|
75754
75754
|
throw userError("Supabase credentials not configured — run `cerefox init` first.");
|
|
@@ -75779,7 +75779,7 @@ async function action19(dir, options) {
|
|
|
75779
75779
|
title: basename3(file, extname4(file)),
|
|
75780
75780
|
source: options.source ?? "cli",
|
|
75781
75781
|
projectName: options.projectName ?? null,
|
|
75782
|
-
metadata,
|
|
75782
|
+
metadata: metadata ?? null,
|
|
75783
75783
|
updateExisting: Boolean(options.updateIfExists),
|
|
75784
75784
|
author,
|
|
75785
75785
|
authorType,
|
|
@@ -76447,9 +76447,9 @@ function registerMcp(program2) {
|
|
|
76447
76447
|
init_cli_core();
|
|
76448
76448
|
init_client();
|
|
76449
76449
|
async function action26(options) {
|
|
76450
|
-
const metadataFilter = parseJsonObjectArg(options.metadataFilter, "--metadata-filter");
|
|
76451
|
-
if (
|
|
76452
|
-
throw userError("
|
|
76450
|
+
const metadataFilter = parseJsonObjectArg(options.metadataFilter, "--metadata-filter") ?? {};
|
|
76451
|
+
if (Object.keys(metadataFilter).length === 0 && !options.projectName && !options.updatedSince && !options.createdSince) {
|
|
76452
|
+
throw userError("Provide at least one of: --metadata-filter, --project-name, --updated-since, or --created-since.", `Examples: --metadata-filter '{"type":"decision-log"}' · --project-name "research" (lists that project's docs).`);
|
|
76453
76453
|
}
|
|
76454
76454
|
const limit = parsePositiveInt(options.limit, "--limit", 10);
|
|
76455
76455
|
const maxBytes = parseNonNegativeInt(options.maxBytes, "--max-bytes", 200000);
|
|
@@ -76509,7 +76509,7 @@ async function action26(options) {
|
|
|
76509
76509
|
}
|
|
76510
76510
|
}
|
|
76511
76511
|
function registerMetadataSearch(program2) {
|
|
76512
|
-
program2.command("metadata-search").description("Find documents by metadata criteria (no text query).").
|
|
76512
|
+
program2.command("metadata-search").description("Find or list documents by metadata, project, or time criteria (no text query).").option("-f, --metadata-filter <json>", "JSON object; only docs whose metadata contains ALL pairs are returned. Optional — omit to list by --project-name / time range alone (at least one criterion is required).").option("-p, --project-name <name>", "Filter to a specific project.").option("--updated-since <iso>", "Only docs updated on/after this ISO timestamp.").option("--created-since <iso>", "Only docs created on/after this ISO timestamp.").option("--include-content", "Include full document text in results.").option("-l, --limit <n>", "Maximum docs to return.", "10").option("--max-bytes <n>", "Response size budget in bytes (with --include-content).", "200000").option("-r, --requestor <name>", "Agent / user name (usage log).").option("--json", "Emit machine-readable JSON.").action(action26);
|
|
76513
76513
|
}
|
|
76514
76514
|
|
|
76515
76515
|
// src/cli/commands/reindex.ts
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
* docs/specs/polish-and-distribution-design.md §10d.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
export const HELP_FULL = "# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **10 MCP tools** (9 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.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `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
|
|
14
|
+
export const HELP_FULL = "# Cerefox Knowledge Base -- Agent Quick Reference\n\nCerefox is a persistent, shared knowledge base. You have **10 MCP tools** (9 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.\n\n## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `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` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project's docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc's project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |\n\n## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., \"Claude Code\", \"archiver\"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user's `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` (\"decision-log\", \"research\", \"design-doc\") and `status` (\"active\", \"draft\").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **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.\n8. **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.\n9. **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.\n10. **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`.\n\n## Update Workflow (ID-based -- preferred)\n\n```\nsearch(\"topic\") -> find doc [id: abc123] -> get_document(abc123) -> note its content_hash -> modify ->\ningest(title=\"Same Title\", content=\"...\", document_id=\"abc123\",\n expected_content_hash=\"<the hash you read>\", author=\"my-agent\")\n```\n\nOn a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.\n\n## Update Workflow (title-based -- fallback)\n\n```\nsearch(\"topic\") -> find doc (note its hash) -> modify ->\ningest(title=\"Same Title\", content=\"...\", update_if_exists=true,\n expected_content_hash=\"<the hash you read>\", author=\"my-agent\")\n```\n\n## Catch-Up Workflow\n\n```\nmetadata_search(metadata_filter={\"type\": \"decision-log\"}, updated_since=\"2026-03-28T00:00:00Z\")\n```\n\n## CLI fallback (when MCP is unavailable)\n\nIf `cerefox_search` is not in your tool list, your user has likely installed the Cerefox CLI. The canonical invocation is plain **`cerefox <subcommand>`** (the TypeScript CLI, installed via `npm install -g @cerefox/memory`). It uses a resource-verb shape (`cerefox document get`, `cerefox project list`, …). The legacy Python `uv run cerefox` is now a frozen husk as of v0.9 — only `uv run cerefox mcp` still works.\n\nSame operations, same conventions. Full reference: [`docs/guides/cli.md`](docs/guides/cli.md). CLI flag names match MCP parameter names exactly (e.g. `metadata_filter` ↔ `--metadata-filter`); common flags also have single-letter short forms (`-f`, `-p`, `-c`, `-m`, `-u`, `-a`, `-r`). Use the canonical long name (what `--help` shows) or its short form — there are no long-form aliases like `--filter` or `--count`.\n\n| MCP tool | CLI |\n|---|---|\n| `cerefox_search` | `cerefox search \"<q>\" --requestor \"<your-name>\"` |\n| `cerefox_ingest` (paste) | `printf '...' \\| cerefox document ingest --paste --title \"<t>\" --author \"<your-name>\" --author-type agent` |\n| `cerefox_ingest` (update by ID) | `printf '...' \\| cerefox document ingest --paste --title \"<t>\" --document-id \"<uuid>\" --expected-content-hash \"<hash>\" --author \"<your-name>\" --author-type agent` |\n| `cerefox_get_document` | `cerefox document get <id> --version-id <vid> --requestor \"<your-name>\"` |\n| `cerefox_list_versions` | `cerefox document version list <id> --requestor \"<your-name>\"` |\n| `cerefox_list_projects` | `cerefox project list --requestor \"<your-name>\"` |\n| `cerefox_list_metadata_keys` | `cerefox metadata keys` |\n| `cerefox_metadata_search` | `cerefox metadata search --metadata-filter '<json>' --requestor \"<your-name>\"` (list a project: `cerefox document list --project <name>`) |\n| `cerefox_set_document_projects` | `cerefox document set-projects <id> <name...> --author \"<your-name>\" --author-type agent` (or `--clear` to remove all) |\n| `cerefox_get_audit_log` | `cerefox audit list --requestor \"<your-name>\"` (add `--json` for scripted access) |\n| `cerefox_get_help` | `cerefox guides show agent-quick-reference` (or `cerefox guides list` for the full bundled-docs index) |\n\n**Set identity on every call**, exactly as you would on MCP:\n- Writes (`document ingest`, `document ingest-dir`): `--author \"<your-name>\" --author-type agent`\n- Reads: `--requestor \"<your-name>\"`\n\nOr have your user set `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` in their `.env` to apply defaults once.\n";
|
|
15
15
|
|
|
16
16
|
/** Sections keyed by their H2 heading text (lower-cased for matching). */
|
|
17
17
|
export const HELP_SECTIONS: Record<string, string> = {
|
|
18
|
-
"Tools": "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `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
|
|
18
|
+
"Tools": "## Tools\n\n| Tool | Purpose | Key params |\n|------|---------|------------|\n| `cerefox_search` | Find documents (hybrid FTS + semantic) | `query` (required), `project_name`, `metadata_filter`, `requestor` |\n| `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` |\n| `cerefox_get_document` | Get full document by ID (header includes `content_hash` — the update token) | `document_id` (required) |\n| `cerefox_list_versions` | Version history of a document | `document_id` (required) |\n| `cerefox_metadata_search` | Find or list docs by metadata, project, or time (no text query) | `metadata_filter`, `project_name` (list a project's docs), `updated_since`, `include_content` — **at least one** of metadata_filter/project_name/updated_since/created_since |\n| `cerefox_list_metadata_keys` | Discover available metadata keys | (none required) |\n| `cerefox_list_projects` | List all projects | (none required) |\n| `cerefox_set_document_projects` | Set doc's project memberships to exactly the given list (destructive replace; metadata-only, no content change) | `document_id`, `project_names` (required) |\n| `cerefox_get_audit_log` | Query write operation history | `document_id`, `author`, `operation`, `since` |\n| `cerefox_get_help` | Retrieve Cerefox conventions (this reference) over MCP. **Call this whenever uncertain.** | `topic` (optional, case-insensitive H2 substring match) |",
|
|
19
19
|
"Essential Rules": "## Essential Rules\n\n1. **Search before ingesting** -- check if the document exists first.\n2. **Prefer ID-based updates** -- pass `document_id` from search results for deterministic updates. Falls back to title-matching with `update_if_exists: true`.\n3. **Set `author`/`requestor`** to your name on every call (e.g., \"Claude Code\", \"archiver\"). On MCP, pass as parameters. On CLI, pass `--author`/`--author-type`/`--requestor` flags, or rely on `CEREFOX_AUTHOR_NAME`/`CEREFOX_AUTHOR_TYPE`/`CEREFOX_REQUESTOR_NAME` env vars set in the user's `.env`.\n4. **Use `document_id` from search results** `[id: uuid]` for get_document and list_versions.\n5. **Add metadata** -- at minimum `type` (\"decision-log\", \"research\", \"design-doc\") and `status` (\"active\", \"draft\").\n6. **Write structured Markdown** with H1/H2/H3 headings for good chunking and search.\n7. **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.\n8. **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.\n9. **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.\n10. **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`.",
|
|
20
20
|
"Update Workflow (ID-based -- preferred)": "## Update Workflow (ID-based -- preferred)\n\n```\nsearch(\"topic\") -> find doc [id: abc123] -> get_document(abc123) -> note its content_hash -> modify ->\ningest(title=\"Same Title\", content=\"...\", document_id=\"abc123\",\n expected_content_hash=\"<the hash you read>\", author=\"my-agent\")\n```\n\nOn a **conflict** error: get_document again (fresh content + fresh hash) -> merge your changes -> retry with the new hash.",
|
|
21
21
|
"Update Workflow (title-based -- fallback)": "## Update Workflow (title-based -- fallback)\n\n```\nsearch(\"topic\") -> find doc (note its hash) -> modify ->\ningest(title=\"Same Title\", content=\"...\", update_if_exists=true,\n expected_content_hash=\"<the hash you read>\", author=\"my-agent\")\n```",
|
|
@@ -71,7 +71,10 @@ async function handler(
|
|
|
71
71
|
const project_name = args.project_name as string | undefined;
|
|
72
72
|
const project_names_raw = args.project_names;
|
|
73
73
|
const source = (args.source as string | undefined) ?? "agent";
|
|
74
|
-
|
|
74
|
+
// null = "not provided": the RPC keeps existing metadata on update and uses
|
|
75
|
+
// {} on create (v0.11.1 — defaulting to {} here used to wipe a document's
|
|
76
|
+
// tags on every content update that didn't re-pass them).
|
|
77
|
+
const metadata = (args.metadata as Record<string, unknown> | undefined) ?? null;
|
|
75
78
|
const update_if_exists = (args.update_if_exists as boolean | undefined) ?? false;
|
|
76
79
|
const author = (args.author as string | undefined) ?? "mcp-agent";
|
|
77
80
|
const author_type = "agent"; // MCP path is always agent
|
|
@@ -1045,7 +1045,10 @@ $$;
|
|
|
1045
1045
|
--
|
|
1046
1046
|
-- Parameters:
|
|
1047
1047
|
-- p_document_id : NULL for create, UUID for update
|
|
1048
|
-
-- p_title, p_source, p_source_path, p_content_hash
|
|
1048
|
+
-- p_title, p_source, p_source_path, p_content_hash : document fields
|
|
1049
|
+
-- p_metadata : JSONB metadata. NULL = "not provided" → create uses '{}',
|
|
1050
|
+
-- update keeps the existing metadata (v0.11.1). Pass '{}'
|
|
1051
|
+
-- explicitly to clear all metadata.
|
|
1049
1052
|
-- p_review_status : 'approved' or 'pending_review' (based on author_type)
|
|
1050
1053
|
-- p_chunks : JSONB array of chunk objects, each with:
|
|
1051
1054
|
-- chunk_index, heading_path, heading_level, title,
|
|
@@ -1075,7 +1078,10 @@ CREATE FUNCTION cerefox_ingest_document(
|
|
|
1075
1078
|
p_source TEXT DEFAULT 'agent',
|
|
1076
1079
|
p_source_path TEXT DEFAULT NULL,
|
|
1077
1080
|
p_content_hash TEXT DEFAULT '',
|
|
1078
|
-
|
|
1081
|
+
-- NULL = "not provided": create uses '{}', update KEEPS existing metadata
|
|
1082
|
+
-- (v0.11.1 fix — content updates without metadata used to wipe tags).
|
|
1083
|
+
-- Pass '{}' explicitly to deliberately clear all metadata.
|
|
1084
|
+
p_metadata JSONB DEFAULT NULL,
|
|
1079
1085
|
p_review_status TEXT DEFAULT 'approved',
|
|
1080
1086
|
p_chunks JSONB DEFAULT '[]',
|
|
1081
1087
|
p_author TEXT DEFAULT 'unknown',
|
|
@@ -1181,13 +1187,14 @@ BEGIN
|
|
|
1181
1187
|
SELECT sv.version_id INTO v_version_id
|
|
1182
1188
|
FROM cerefox_snapshot_version(v_doc_id, p_source_label, p_retention_hours, p_cleanup_enabled) sv;
|
|
1183
1189
|
|
|
1184
|
-
-- Update document record
|
|
1190
|
+
-- Update document record. metadata: NULL = keep existing (v0.11.1 —
|
|
1191
|
+
-- a content update without metadata must not wipe the document's tags).
|
|
1185
1192
|
UPDATE cerefox_documents SET
|
|
1186
1193
|
title = p_title,
|
|
1187
1194
|
source = p_source,
|
|
1188
1195
|
source_path = COALESCE(p_source_path, source_path),
|
|
1189
1196
|
content_hash = p_content_hash,
|
|
1190
|
-
metadata = p_metadata,
|
|
1197
|
+
metadata = COALESCE(p_metadata, metadata),
|
|
1191
1198
|
chunk_count = v_chunk_count,
|
|
1192
1199
|
total_chars = v_total_chars,
|
|
1193
1200
|
review_status = v_status,
|
|
@@ -1202,7 +1209,7 @@ BEGIN
|
|
|
1202
1209
|
title, source, source_path, content_hash, metadata,
|
|
1203
1210
|
chunk_count, total_chars, review_status
|
|
1204
1211
|
) VALUES (
|
|
1205
|
-
p_title, p_source, p_source_path, p_content_hash, p_metadata,
|
|
1212
|
+
p_title, p_source, p_source_path, p_content_hash, COALESCE(p_metadata, '{}'::JSONB),
|
|
1206
1213
|
v_chunk_count, v_total_chars, v_status
|
|
1207
1214
|
)
|
|
1208
1215
|
RETURNING id INTO v_doc_id;
|
|
@@ -1760,7 +1767,7 @@ SET search_path = public, pg_catalog
|
|
|
1760
1767
|
AS $$
|
|
1761
1768
|
-- Keep in lockstep with the `@version:` marker in schema.sql (cut_release.ts
|
|
1762
1769
|
-- enforces it). Bump whenever schema.sql OR rpcs.sql changes.
|
|
1763
|
-
SELECT '0.
|
|
1770
|
+
SELECT '0.6.0'::TEXT;
|
|
1764
1771
|
$$;
|
|
1765
1772
|
|
|
1766
1773
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
-- Requires extensions: vector (pgvector), uuid-ossp
|
|
6
6
|
-- These are enabled at the top of db_deploy.py before this file is applied.
|
|
7
7
|
--
|
|
8
|
-
-- @version: 0.
|
|
8
|
+
-- @version: 0.6.0
|
|
9
9
|
-- The `@version` marker above is read by the schema-version-mismatch banner
|
|
10
10
|
-- (see /api/v1/schema-version). Bump it whenever schema.sql OR rpcs.sql
|
|
11
11
|
-- changes in a way that requires `cerefox server deploy` to be re-run —
|
|
@@ -17,7 +17,9 @@ import { isVersionRequest, versionResponse } from "../../../_shared/ef-meta/inde
|
|
|
17
17
|
* content string required Markdown content
|
|
18
18
|
* project_name string optional Project to assign to (looked up by name, created if absent)
|
|
19
19
|
* source string optional Origin label (default: "agent")
|
|
20
|
-
* metadata object optional Arbitrary JSONB metadata
|
|
20
|
+
* metadata object optional Arbitrary JSONB metadata. Omitted on an
|
|
21
|
+
* update → existing metadata is KEPT
|
|
22
|
+
* (v0.11.1); pass {} explicitly to clear.
|
|
21
23
|
*
|
|
22
24
|
* Response: { document_id, title, chunk_count, project_id? }
|
|
23
25
|
*/
|
|
@@ -464,7 +466,10 @@ Deno.serve(async (req: Request) => {
|
|
|
464
466
|
});
|
|
465
467
|
}
|
|
466
468
|
|
|
467
|
-
|
|
469
|
+
// metadata: null = "not provided" — the RPC keeps existing metadata on
|
|
470
|
+
// update and uses {} on create (v0.11.1; a `= {}` default here used to wipe
|
|
471
|
+
// a document's tags on every content update that didn't re-pass them).
|
|
472
|
+
const { title, content, document_id = null, project_name, source = "agent", metadata = null, update_if_exists = false, author = "agent", author_type = "agent", expected_content_hash = null, last_write_wins = false } = body;
|
|
468
473
|
|
|
469
474
|
// Validate + normalize project_names if provided (full-set destructive form)
|
|
470
475
|
let project_names: string[] | null = null;
|
package/docs/guides/cli.md
CHANGED
|
@@ -43,7 +43,7 @@ cerefox document ingest --paste --title "<title>" [OPTIONS] # stdin
|
|
|
43
43
|
| `--title` | `-t` | str | filename stem | Document title. Required with `--paste`. |
|
|
44
44
|
| `--project-name` | `--project`, `-p` | str | _none_ | Project name to assign the document to (created if missing). |
|
|
45
45
|
| `--paste` | — | flag | off | Read markdown from stdin. Requires `--title`. |
|
|
46
|
-
| `--metadata` | `-m` | JSON |
|
|
46
|
+
| `--metadata` | `-m` | JSON | _not provided_ | Extra metadata as a JSON object, e.g. `'{"tags":["work"]}'`. **On update, omitting this keeps the document's existing metadata** (v0.11.1); pass `'{}'` to deliberately clear all metadata. |
|
|
47
47
|
| `--update-if-exists` | `-u` | flag | off | Title/source-path-based fallback update. Mutually exclusive with `--document-id`. |
|
|
48
48
|
| `--document-id` | `-i` | UUID | _none_ | Deterministic ID-based update. Errors if the document doesn't exist. |
|
|
49
49
|
| `--expected-content-hash` | — | sha256 | _none_ | **Required on content updates** (v0.11 optimistic concurrency): the `content_hash` of the version this edit is based on, shown by `cerefox document get` / `cerefox search`. Stale → conflict error (re-read, merge, retry). |
|
|
@@ -410,8 +410,8 @@ cerefox metadata search --metadata-filter '<json>' [OPTIONS]
|
|
|
410
410
|
|
|
411
411
|
| Flag | Type | Default | Description |
|
|
412
412
|
|---|---|---|---|
|
|
413
|
-
| `--metadata-filter <json>` (`-f`) | JSON |
|
|
414
|
-
| `--project-name <name>` (`-p`) | str | _none_ | Filter by project name. |
|
|
413
|
+
| `--metadata-filter <json>` (`-f`) | JSON | _none_ | Metadata filter, e.g. `'{"type":"decision-log"}'`. Optional since v0.11.1 — at least one of filter / `--project-name` / `--updated-since` / `--created-since` is required (parity with the MCP tool). |
|
|
414
|
+
| `--project-name <name>` (`-p`) | str | _none_ | Filter by project name. Sufficient on its own to list that project's documents. |
|
|
415
415
|
| `--updated-since TEXT` | ISO-8601 | _none_ | Documents updated after this timestamp. |
|
|
416
416
|
| `--created-since TEXT` | ISO-8601 | _none_ | Documents created after this timestamp. |
|
|
417
417
|
| `--limit INTEGER` | int | `10` | Max results. |
|
|
@@ -609,7 +609,7 @@ In the action editor, paste this schema (replace `<your-project-ref>`):
|
|
|
609
609
|
openapi: 3.1.0
|
|
610
610
|
info:
|
|
611
611
|
title: Cerefox Knowledge Base
|
|
612
|
-
version: 2.
|
|
612
|
+
version: 2.1.0
|
|
613
613
|
servers:
|
|
614
614
|
- url: https://<your-project-ref>.supabase.co/functions/v1
|
|
615
615
|
paths:
|
|
@@ -728,6 +728,10 @@ paths:
|
|
|
728
728
|
default: agent
|
|
729
729
|
metadata:
|
|
730
730
|
type: object
|
|
731
|
+
description: >
|
|
732
|
+
Arbitrary JSON metadata. On an UPDATE, omitting this keeps
|
|
733
|
+
the document's existing metadata (v2.1.0); pass {} to
|
|
734
|
+
deliberately clear all tags.
|
|
731
735
|
update_if_exists:
|
|
732
736
|
type: boolean
|
|
733
737
|
default: false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cerefox/memory",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Cerefox — user-owned shared memory for AI agents. The local TypeScript runtime: stdio MCP server in v0.4; CLI binary added in v0.5; in-process web server in v0.6; ingestion pipeline in v0.7.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/fstamatelopoulos/cerefox",
|