@cerefox/memory 1.2.1 → 1.3.0-beta.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.
@@ -1293,6 +1293,10 @@ $$;
1293
1293
  DROP FUNCTION IF EXISTS cerefox_ingest_document(UUID, TEXT, TEXT, TEXT, TEXT, JSONB, TEXT, JSONB, TEXT, TEXT, TEXT, INT, BOOLEAN);
1294
1294
  DROP FUNCTION IF EXISTS cerefox_ingest_document(UUID, TEXT, TEXT, TEXT, TEXT, JSONB, TEXT, JSONB, TEXT, TEXT, TEXT, INT, BOOLEAN, TEXT, BOOLEAN);
1295
1295
  DROP FUNCTION IF EXISTS cerefox_ingest_document(UUID, TEXT, TEXT, TEXT, TEXT, JSONB, TEXT, JSONB, TEXT, TEXT, TEXT, INT, BOOLEAN, TEXT, BOOLEAN, SMALLINT);
1296
+ -- iter-33: return shape gains content_hash + size_warning, so the 16-arg form
1297
+ -- must be dropped before the 17-arg CREATE below (Postgres will not replace a
1298
+ -- function whose RETURNS TABLE changed).
1299
+ DROP FUNCTION IF EXISTS cerefox_ingest_document(UUID, TEXT, TEXT, TEXT, TEXT, JSONB, TEXT, JSONB, TEXT, TEXT, TEXT, INT, BOOLEAN, TEXT, BOOLEAN, SMALLINT, JSONB);
1296
1300
  CREATE FUNCTION cerefox_ingest_document(
1297
1301
  p_document_id UUID DEFAULT NULL,
1298
1302
  p_title TEXT DEFAULT 'Untitled',
@@ -1324,14 +1328,30 @@ CREATE FUNCTION cerefox_ingest_document(
1324
1328
  -- content_format for the chunks being written (iter-28D). 2 = exact-partition
1325
1329
  -- (blind-stitch reconstruction); default 1 = legacy (E'\n\n'-join). Stamped on
1326
1330
  -- every chunk this call inserts.
1327
- p_content_format SMALLINT DEFAULT 1
1331
+ p_content_format SMALLINT DEFAULT 1,
1332
+ -- iter-33 (partial edits): when NULL, audit behaves exactly as before
1333
+ -- ('create' / 'update-content'). When set, it is a JSONB array of
1334
+ -- {"op": "...", "detail": "..."} and ONE audit entry is written per element,
1335
+ -- so a cerefox_edit batch records what it actually did rather than
1336
+ -- flattening to 'update-content'. NULL-means-today, per the #183 lesson:
1337
+ -- a parameter that substitutes its own concrete default is how store policy
1338
+ -- got silently overridden for a whole release.
1339
+ p_operations JSONB DEFAULT NULL
1328
1340
  )
1329
1341
  RETURNS TABLE (
1330
1342
  document_id UUID,
1331
1343
  chunk_count INT,
1332
1344
  total_chars INT,
1333
1345
  operation TEXT,
1334
- version_id UUID
1346
+ version_id UUID,
1347
+ -- iter-33: the hash just written, on CREATE as well as update (#189). A
1348
+ -- document is now born holding its own concurrency token, so the author
1349
+ -- never has to re-read it or fall back to last_write_wins.
1350
+ content_hash TEXT,
1351
+ -- iter-33: true when the new size crosses `document_size_warning_chars`
1352
+ -- (dormant when that config is unset/0). A signal, never a refusal: an
1353
+ -- insert-only workflow otherwise never sees a document grow.
1354
+ size_warning BOOLEAN
1335
1355
  )
1336
1356
  LANGUAGE plpgsql
1337
1357
  SECURITY DEFINER
@@ -1348,6 +1368,9 @@ DECLARE
1348
1368
  v_chunk JSONB;
1349
1369
  v_snap RECORD;
1350
1370
  v_status TEXT;
1371
+ v_op JSONB; -- iter-33: per-operation audit element
1372
+ v_size_warn_at INT;
1373
+ v_size_warning BOOLEAN := FALSE;
1351
1374
  BEGIN
1352
1375
  -- ── Zero-chunk guard (v0.3.1) ────────────────────────────────────────
1353
1376
  -- Refuse to create or update a document with no chunks. Three reasons:
@@ -1506,21 +1529,68 @@ BEGIN
1506
1529
  setweight(to_tsvector('english', COALESCE(c->>'content', '')), 'B')
1507
1530
  FROM jsonb_array_elements(p_chunks) AS c;
1508
1531
 
1509
- -- ── Audit entry ──────────────────────────────────────────────────
1510
- PERFORM cerefox_create_audit_entry(
1511
- p_document_id := v_doc_id,
1512
- p_version_id := v_version_id,
1513
- p_operation := v_operation,
1514
- p_author := p_author,
1515
- p_author_type := p_author_type,
1516
- p_size_before := CASE WHEN v_operation = 'create' THEN NULL ELSE v_old_chars END,
1517
- p_size_after := v_total_chars,
1518
- p_description := v_operation || ': ' || p_title || ' (' || v_chunk_count || ' chunks, ' || v_total_chars || ' chars)'
1519
- || CASE WHEN p_last_write_wins AND v_operation = 'update-content'
1520
- THEN ' [last-write-wins]' ELSE '' END
1521
- );
1532
+ -- ── Audit entries ────────────────────────────────────────────────
1533
+ -- p_operations NULL (every pre-iter-33 caller): one entry, exactly as before.
1534
+ -- p_operations set (cerefox_insert / cerefox_edit): one entry per operation,
1535
+ -- each under its own operation value, so the trail distinguishes "added to"
1536
+ -- from "rewrote" from "removed" instead of flattening to 'update-content'.
1537
+ -- The CHECK constraint on cerefox_audit_log.operation is the allow-list: a
1538
+ -- handler label that drifts from it aborts this transaction rather than
1539
+ -- silently recording something the readers of the trail cannot interpret.
1540
+ IF p_operations IS NULL OR jsonb_array_length(p_operations) = 0 THEN
1541
+ PERFORM cerefox_create_audit_entry(
1542
+ p_document_id := v_doc_id,
1543
+ p_version_id := v_version_id,
1544
+ p_operation := v_operation,
1545
+ p_author := p_author,
1546
+ p_author_type := p_author_type,
1547
+ p_size_before := CASE WHEN v_operation = 'create' THEN NULL ELSE v_old_chars END,
1548
+ p_size_after := v_total_chars,
1549
+ p_description := v_operation || ': ' || p_title || ' (' || v_chunk_count || ' chunks, ' || v_total_chars || ' chars)'
1550
+ || CASE WHEN p_last_write_wins AND v_operation = 'update-content'
1551
+ THEN ' [last-write-wins]' ELSE '' END
1552
+ );
1553
+ ELSE
1554
+ FOR v_op IN SELECT * FROM jsonb_array_elements(p_operations) LOOP
1555
+ PERFORM cerefox_create_audit_entry(
1556
+ p_document_id := v_doc_id,
1557
+ p_version_id := v_version_id,
1558
+ p_operation := v_op->>'op',
1559
+ p_author := p_author,
1560
+ p_author_type := p_author_type,
1561
+ -- Sizes describe the whole write, so they go on the last entry
1562
+ -- only; per-operation sizes would double-count a single write.
1563
+ p_size_before := NULL,
1564
+ p_size_after := NULL,
1565
+ p_description := COALESCE(v_op->>'detail', v_op->>'op')
1566
+ );
1567
+ END LOOP;
1568
+ -- One sizing entry for the write as a whole.
1569
+ PERFORM cerefox_create_audit_entry(
1570
+ p_document_id := v_doc_id,
1571
+ p_version_id := v_version_id,
1572
+ p_operation := v_operation,
1573
+ p_author := p_author,
1574
+ p_author_type := p_author_type,
1575
+ p_size_before := CASE WHEN v_operation = 'create' THEN NULL ELSE v_old_chars END,
1576
+ p_size_after := v_total_chars,
1577
+ p_description := 'partial edit: ' || p_title || ' ('
1578
+ || jsonb_array_length(p_operations) || ' operation(s), '
1579
+ || v_chunk_count || ' chunks, ' || v_total_chars || ' chars)'
1580
+ );
1581
+ END IF;
1582
+
1583
+ -- ── Size signal (iter-33) ────────────────────────────────────────
1584
+ -- Dormant unless an operator sets a threshold. Never blocks the write: a
1585
+ -- size policy is not a correctness rule, and an agent that only ever
1586
+ -- inserts otherwise never sees the document grow past its split point.
1587
+ v_size_warn_at := cerefox_config_int('document_size_warning_chars', 0);
1588
+ IF v_size_warn_at > 0 AND v_total_chars > v_size_warn_at THEN
1589
+ v_size_warning := TRUE;
1590
+ END IF;
1522
1591
 
1523
- RETURN QUERY SELECT v_doc_id, v_chunk_count, v_total_chars, v_operation, v_version_id;
1592
+ RETURN QUERY SELECT v_doc_id, v_chunk_count, v_total_chars, v_operation,
1593
+ v_version_id, p_content_hash, v_size_warning;
1524
1594
  END;
1525
1595
  $$;
1526
1596
 
@@ -1584,12 +1654,19 @@ SET search_path = public, pg_catalog
1584
1654
  AS $$
1585
1655
  INSERT INTO cerefox_audit_log (
1586
1656
  document_id, version_id, operation, author, author_type,
1587
- size_before, size_after, description
1657
+ size_before, size_after, description, created_at
1588
1658
  )
1589
1659
  VALUES (
1590
1660
  p_document_id, p_version_id, p_operation, p_author,
1591
1661
  CASE WHEN p_author_type IN ('user', 'agent') THEN p_author_type ELSE 'user' END,
1592
- p_size_before, p_size_after, p_description
1662
+ p_size_before, p_size_after, p_description,
1663
+ -- clock_timestamp(), not the NOW() default: NOW() is the TRANSACTION's
1664
+ -- start time, so every audit entry written by one cerefox_edit batch
1665
+ -- would share a timestamp and the order of operations inside the batch
1666
+ -- would be unrecoverable from the trail (iter-33). clock_timestamp()
1667
+ -- advances within a transaction, so entries stay orderable. Outside a
1668
+ -- batch this is indistinguishable from the old behaviour.
1669
+ clock_timestamp()
1593
1670
  )
1594
1671
  RETURNING id AS audit_id, cerefox_audit_log.created_at;
1595
1672
  $$;
@@ -2148,7 +2225,12 @@ DECLARE
2148
2225
  -- surviving history depended on who saved last.
2149
2226
  'version_retention_hours', 'version_cleanup_enabled',
2150
2227
  -- Optional features, off by default (iteration 29).
2151
- 'relations_enabled'
2228
+ 'relations_enabled',
2229
+ -- Iteration 33: flag writes that push a document past this many chars
2230
+ -- (0 = off). Partial edits make writes cheap, so an insert-only agent
2231
+ -- never assembles the document and never sees it grow past its split
2232
+ -- point. A signal in the write's response, never a refusal.
2233
+ 'document_size_warning_chars'
2152
2234
  ];
2153
2235
  BEGIN
2154
2236
  IF NOT (p_key = ANY(v_allowed)) THEN
@@ -2343,7 +2425,10 @@ SET search_path = public, pg_catalog
2343
2425
  AS $$
2344
2426
  -- Keep in lockstep with the `@version:` marker in schema.sql (cut_release.ts
2345
2427
  -- enforces it). Bump whenever schema.sql OR rpcs.sql changes.
2346
- SELECT '0.10.6'::TEXT;
2428
+ -- 0.11.0 supersedes 0.10.6 (v1.2.1, #191): this branch carries that fix plus
2429
+ -- the partial-edit surface, and both migrations (0019, 0020) are in the
2430
+ -- sequence, so a store deploying this gets everything from both lines.
2431
+ SELECT '0.11.0'::TEXT;
2347
2432
  $$;
2348
2433
 
2349
2434
  -- ── cerefox_content_format_stats ─────────────────────────────────────────────
@@ -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.10.6
8
+ -- @version: 0.11.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 —
@@ -125,7 +125,11 @@ CREATE TABLE IF NOT EXISTS cerefox_audit_log (
125
125
  operation IN ('create', 'update-content', 'update-metadata', 'delete',
126
126
  'status-change', 'archive', 'unarchive', 'restore',
127
127
  -- iteration 29: graph edges are auditable writes too
128
- 'relation-set', 'relation-delete')
128
+ 'relation-set', 'relation-delete',
129
+ -- iteration 33: partial edits. Distinct from 'update-content'
130
+ -- so the trail separates "added to" from "rewrote" from
131
+ -- "removed" — one entry per operation in a cerefox_edit batch.
132
+ 'insert', 'replace-section', 'delete-section')
129
133
  ),
130
134
  CONSTRAINT cerefox_audit_log_author_type_check CHECK (author_type IN ('user', 'agent'))
131
135
  );
@@ -753,6 +753,10 @@ Deno.serve(async (req: Request) => {
753
753
  title: title.trim(),
754
754
  chunk_count: chunks.length,
755
755
  total_chars: totalChars,
756
+ // #189: the concurrency token, on CREATE as well as update. Without it the
757
+ // author of a new document had to re-read it, or pass last_write_wins, to
758
+ // make its first edit — and callers took the second.
759
+ content_hash: ingestResult[0].content_hash ?? contentHash,
756
760
  project_id: projectId,
757
761
  project_name: project_name ?? null,
758
762
  }),
@@ -46,7 +46,7 @@ cerefox document ingest --paste --title "<title>" [OPTIONS] # stdin
46
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
- | `--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). |
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` — and printed by **every write, including create** (v1.3.0), so a script can chain edits without re-reading. Stale → conflict error (re-read, merge, retry). |
50
50
  | `--last-write-wins` | — | flag | off | Skip the concurrency check and overwrite regardless of concurrent changes. For re-sync flows where an external source of truth makes conflicts meaningless. Recorded in the audit log. |
51
51
  | `--source` | — | str | `paste` / `file` | Source label recorded on the document. |
52
52
  | `--author` | — | str | `CEREFOX_AUTHOR_NAME` or `unknown` | Audit-log author identity. |
@@ -611,7 +611,7 @@ cerefox config set relations_enabled true # tools appear in every agent's lis
611
611
  cerefox config set relations_enabled false # hidden again; no data removed
612
612
  ```
613
613
 
614
- Agents see 10 tools with the flag off and 14 with it on. See
614
+ Agents see 12 tools with the flag off and 16 with it on. See
615
615
  [`configuration.md`](configuration.md) for the full runtime-config surface.
616
616
 
617
617
  ### `cerefox config list` / `cerefox config get` / `cerefox config set`
@@ -720,7 +720,9 @@ Every MCP parameter has an exact-name CLI flag (kebab-cased). Short forms exist
720
720
  | `cerefox_search(query, match_count, project_name, metadata_filter, requestor)` | `cerefox search "<q>" --match-count N --project-name <name> --metadata-filter '<json>' --requestor <name>` |
721
721
  | `cerefox_ingest(title, content, project_name, metadata, update_if_exists, document_id, expected_content_hash, last_write_wins, source, author, author_type)` (file) | `cerefox document ingest <path> --title <t> --project-name <n> --metadata '<json>' --update-if-exists\|--document-id <uuid> --expected-content-hash <hash>\|--last-write-wins --source <s> --author <a> --author-type <t>` |
722
722
  | `cerefox_ingest(...)` (paste) | `printf '...' \| cerefox document ingest --paste --title "<t>"` (same flags) |
723
- | `cerefox_get_document(document_id, version_id, requestor)` | `cerefox document get <id> --version-id <vid> --requestor <name>` |
723
+ | `cerefox_get_document(document_id, version_id, outline, requestor)` | `cerefox document get <id> --version-id <vid> --outline --requestor <name>` |
724
+ | `cerefox_insert(document_id, text, position, anchor_heading, section_part, expected_content_hash, requestor)` | `cerefox document insert <id> -t <text\|-\|@file> -p <position> -a <anchor> --section-part <part> --expected-hash <hash> --requestor <name>` |
725
+ | `cerefox_edit(document_id, operations, expected_content_hash, requestor)` | `cerefox document edit-parts <id> -o <json\|-\|@file> --expected-hash <hash> --requestor <name>` |
724
726
  | `cerefox_list_versions(document_id, requestor)` | `cerefox document version list <id> --requestor <name>` |
725
727
  | `cerefox_list_projects(requestor)` | `cerefox project list --requestor <name>` |
726
728
  | `cerefox_set_document_projects(document_id, project_names, author)` | `cerefox document set-projects <id> <name...> --author <a> --author-type <t>` (or `--clear` to remove all) |
@@ -122,6 +122,14 @@ This handles intermittent OpenAI API errors (500s) that would otherwise cause se
122
122
  > **dormant**: the table stays empty, `lifecycle_status` defaults to `active`,
123
123
  > search is untouched, and the tools do not appear in any agent's tool list
124
124
  > until you opt in with `cerefox config set relations_enabled true`.
125
+ >
126
+ > **Size signal for partial edits.** `document_size_warning_chars` (default `0`
127
+ > = off) makes every write report when a document has grown past the given
128
+ > size. It exists because partial edits (v1.3.0) make writes cheap: an agent
129
+ > that only ever inserts never assembles the document, so it never sees it
130
+ > approach the point where it should be split. A signal only — writes are never
131
+ > blocked. `cerefox config set document_size_warning_chars 50000` mirrors the
132
+ > maintainers' own split-at-~50K practice.
125
133
 
126
134
  > **Deployment-wide defaults (v1.1.0+).** `min_search_score`,
127
135
  > `min_term_coverage`, and `search_alpha` can also be set **once, in the
@@ -72,7 +72,7 @@ in the container.
72
72
  - **Easiest:** `cerefox-local configure-agent` wires it up (registers an MCP server named
73
73
  `cerefox-local` with Claude Code if the `claude` CLI is present, else prints the snippet).
74
74
  - **Manual:** point the client at `command: cerefox-local, args: ["mcp"]` (stdio). That proxies
75
- to `cerefox mcp` in the container; the same 10 tools, identical behavior to every other path.
75
+ to `cerefox mcp` in the container; the same 12 core tools, identical behavior to every other path.
76
76
  - The cloud paths above (remote Edge Function, GPT Actions) **do not apply** to a local-only
77
77
  install — there are no Edge Functions.
78
78
 
@@ -131,7 +131,7 @@ in the container.
131
131
 
132
132
  ### What it is
133
133
 
134
- The local Cerefox MCP server runs on your machine and exposes the same 10 tools as the remote
134
+ The local Cerefox MCP server runs on your machine and exposes the same 12 core tools as the remote
135
135
  Edge Function, communicating with clients over stdio.
136
136
 
137
137
  The local server ships as an npm package — **[`@cerefox/memory`](https://www.npmjs.com/package/@cerefox/memory)** — built with the official `@modelcontextprotocol/sdk`.
@@ -186,7 +186,7 @@ Once configured, every Path A client has these tools:
186
186
  | `cerefox_set_document_projects` | Set a document's project memberships to exactly the given list (destructive replace; metadata-only, no content change). Use `cerefox_ingest` with singular `project_name` for non-destructive "add". |
187
187
  | `cerefox_get_help` | Retrieve Cerefox conventions (the same content as `AGENT_QUICK_REFERENCE.md`) over MCP. Optional `topic` parameter does a case-insensitive H2 substring match. Call this whenever you are uncertain. |
188
188
 
189
- > All 10 tools are available on both Path A (local and remote MCP) and Path B (GPT Actions
189
+ > All 12 core tools are available on both Path A (local and remote MCP) and Path B (GPT Actions
190
190
  > via dedicated Edge Functions, except `cerefox_get_help` which is MCP-only). MCP tools use
191
191
  > `project_name` (human-readable); primitive Edge Functions (Path B) use `project_id` (UUID).
192
192
 
@@ -212,7 +212,7 @@ For the full tool reference, search Cerefox for "How AI Agents Use Cerefox".
212
212
  After setup, ask your client:
213
213
 
214
214
  > "What tools do you have available?"
215
- > Expected: 10 tools listed (`cerefox_search`, `cerefox_ingest`, `cerefox_get_document`,
215
+ > Expected: 12 tools listed (`cerefox_search`, `cerefox_ingest`, `cerefox_insert`, `cerefox_edit`, `cerefox_get_document`,
216
216
  > `cerefox_list_versions`, `cerefox_list_projects`, `cerefox_list_metadata_keys`,
217
217
  > `cerefox_metadata_search`, `cerefox_set_document_projects`, `cerefox_get_audit_log`,
218
218
  > `cerefox_get_help`).
@@ -306,7 +306,7 @@ pick it up automatically.
306
306
  to primitive Edge Functions. This means each MCP tool call costs a single Edge Function
307
307
  invocation.
308
308
 
309
- A single HTTPS URL gives any remote-capable MCP client all 10 tools with full hybrid
309
+ A single HTTPS URL gives any remote-capable MCP client all 12 core tools with full hybrid
310
310
  search -- no Python, no `uv`, no local repository clone needed.
311
311
 
312
312
  **URL format:**
@@ -487,7 +487,7 @@ Replace `<your-project-ref>` with your Supabase project ref.
487
487
  **Step 3 — Verify:**
488
488
 
489
489
  Launch Codex and use the `/mcp` slash command to confirm the `cerefox` server is connected
490
- and all 10 tools are listed.
490
+ and all 12 tools are listed.
491
491
 
492
492
  **Notes:**
493
493
  - `bearer_token_env_var` is the **name** of the env var (e.g. `"CEREFOX_ACCESS_TOKEN"`), not the
@@ -610,7 +610,7 @@ In the action editor, paste this schema (replace `<your-project-ref>`):
610
610
  openapi: 3.1.0
611
611
  info:
612
612
  title: Cerefox Knowledge Base
613
- version: 3.0.0
613
+ version: 3.1.0
614
614
  servers:
615
615
  - url: https://<your-project-ref>.supabase.co/functions/v1
616
616
  paths:
@@ -780,7 +780,9 @@ paths:
780
780
  project_id?, project_name?, # set when a project was assigned on create
781
781
  skipped?, # true when identical content was deduplicated
782
782
  updated?, # true when an existing doc was updated
783
- content_hash?, # the NEW hash after an update (the next edit's token)
783
+ content_hash, # the new hash returned on CREATE as well as
784
+ # update, so a new document is born holding
785
+ # its own concurrency token (#189)
784
786
  message?, # human note on dedup/skip/update
785
787
  note? } # note when a flag (e.g. update_if_exists) was overridden
786
788
  '400':
@@ -1134,7 +1136,7 @@ user + `CEREFOX_OAUTH_OWNER_ID` pin, and register the Claude OAuth App
1134
1136
  Client Secret from the pre-registered OAuth App (setup-supabase Step 7d).
1135
1137
  5. Save. Claude runs the OAuth flow → redirects you to the **Cerefox consent page** (sign
1136
1138
  in with the owner email/password from Step 7c, then **Allow**) → returns to Claude. The
1137
- connector shows as connected with **10 tools**. (If you've approved before, Supabase
1139
+ connector shows as connected with **12 tools** (16 if you have enabled document relations). (If you've approved before, Supabase
1138
1140
  auto-consents and the page just flashes through — that's expected.)
1139
1141
  6. **Mobile**: connectors are account-level, so `CerefoxMCP` appears in the Claude mobile
1140
1142
  app automatically — run one search from your phone to confirm.
@@ -74,7 +74,7 @@ paths go through **Edge Functions**, which the free tier caps at 500,000/month:
74
74
  500K/month is generous for a single human-driven agent. But **automated or
75
75
  high-frequency agents on the remote path** can approach it. The lever: point those
76
76
  agents at the **local stdio MCP server** (`cerefox mcp`) instead of the remote Edge
77
- Function — it exposes the identical 10 tools, talks to the Data API directly, and
77
+ Function — it exposes the identical 12 core tools (plus the 4 relation tools when enabled), talks to the Data API directly, and
78
78
  costs **zero** Edge Function invocations (bonus: lower latency, and it works offline
79
79
  against a reachable database). If you do exceed the free EF quota, Supabase's Pro
80
80
  plan ($25/mo, 2M invocations included) is the next step.
@@ -124,6 +124,19 @@ bun scripts/backup_create.ts && bun scripts/db_migrate.ts
124
124
 
125
125
  ---
126
126
 
127
+ ## backup_create.ts / backup_restore.ts — thin shims over the CLI
128
+
129
+ > **These delegate to `cerefox backup create` / `cerefox backup restore`.** They
130
+ > used to carry their own capture and restore logic, which is how #166 half-
131
+ > healed: the fixes that taught backups to capture project memberships (v1.0.7),
132
+ > then relations and `lifecycle_status` (v1.1.0), landed in the CLI command and
133
+ > never reached the scripts. Anyone following the pre-migration recipe below got
134
+ > a snapshot missing all of them, silently.
135
+ >
136
+ > They now delegate, so there is one capture path, one restore path, and one
137
+ > format. Prefer the CLI command directly; the scripts remain for the muscle
138
+ > memory and for recipes that already reference them.
139
+
127
140
  ## backup_create.ts — Create a backup
128
141
 
129
142
  Exports all documents, chunks, and metadata to a JSON file in the backup directory. (End users use `cerefox backup create`.)
@@ -135,8 +148,8 @@ bun scripts/backup_create.ts [OPTIONS]
135
148
  | Option | Description |
136
149
  |--------|-------------|
137
150
  | `--label LABEL` | Optional label appended to the filename (e.g. `pre-migration`) |
138
- | `--dir DIR` | Directory to write backup to (default: `./backup-data`) |
139
- | `--git-commit` | Stage and commit the backup file to git after writing |
151
+ | `--dir DIR` | Directory to write backup to (default: `./backups`) |
152
+ | `--git-commit` | Stage and commit the backup file to git after writing. Performed by this script after the snapshot is written — `cerefox backup create --git` is a documented no-op, so the flag is deliberately not forwarded. |
140
153
 
141
154
  Backup filename format: `cerefox-{YYYYMMDDTHHMMSSZ}[-{label}].json`
142
155
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerefox/memory",
3
- "version": "1.2.1",
3
+ "version": "1.3.0-beta.1",
4
4
  "description": "Cerefox — user-owned shared memory for AI agents. CLI + stdio MCP server + web UI + ingestion for a knowledge base on your own Supabase project (or fully self-hosted with Cerefox Local).",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/fstamatelopoulos/cerefox",