@cerefox/memory 1.15.2 → 1.15.3

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.
@@ -0,0 +1,334 @@
1
+ # Running a staging environment alongside production
2
+
3
+ Cerefox can talk to more than one backend from a single machine. This guide sets
4
+ up a **staging** environment — a second Supabase project you can deploy
5
+ pre-release builds to, import production data into, and break freely — while
6
+ production stays untouched.
7
+
8
+ > **Nothing here affects a normal single-environment install.** Every mechanism
9
+ > below is opt-in and inert unless you set `CEREFOX_CONFIG_DIR`. If you never
10
+ > want staging, you can stop reading; `cerefox …` behaves exactly as documented
11
+ > in [`setup-supabase.md`](setup-supabase.md).
12
+
13
+ **Status**: validated end to end — config, database, backups, CLI version, and
14
+ the web server all separate cleanly. One gap remains (agent/MCP wiring); see
15
+ [Known limits](#known-limits).
16
+
17
+ This is a **convention, not a feature**. There is no `--env` flag and no profile
18
+ system to learn: two environment variables and a shell alias do the whole job,
19
+ which is why none of it can destabilise a normal single-environment install.
20
+
21
+ ---
22
+
23
+ ## Why bother
24
+
25
+ Three things, and the third turned out to matter most:
26
+
27
+ - **Upgrades.** A release that changes the schema will run its migrations
28
+ against your real data exactly once. Staging lets you rehearse that on a copy.
29
+ - **Destructive or expensive operations.** `server migrate-format` re-embeds
30
+ every legacy document (real spend, rewrites chunks). Proving it on a copy
31
+ first turns an act of faith into a measurement.
32
+ - **Development.** A store you are willing to break is the cheapest way to turn
33
+ a claim about runtime behaviour into a measurement. During the 1.1.0 cycle this
34
+ found a retry loop executing 68,825 times per request, a `migrate-format` that
35
+ reported success while converting nothing, and a `backup create` that failed
36
+ against older servers — none visible from the code or the test suite. Keep it
37
+ available during development stretches, not only around releases.
38
+
39
+ ---
40
+
41
+ ## 1. Create the staging Supabase project
42
+
43
+ Follow [`setup-supabase.md` Step 1](setup-supabase.md), with two differences:
44
+
45
+ - Name it distinctly (`cerefox-staging`) — the dashboard project switcher is
46
+ your first defense against acting on the wrong database.
47
+ - Pick the **same region as production** if you care about comparable timings.
48
+ A different region is fine functionally; just never compare *speed* across
49
+ the two.
50
+
51
+ The creation-time security options are the same as production, and the
52
+ "automatically expose new tables" setting is worth disabling on both — Cerefox
53
+ grants its tables to `service_role` explicitly.
54
+
55
+ ---
56
+
57
+ ## 2. Give staging its own config directory
58
+
59
+ `CEREFOX_CONFIG_DIR` overrides where Cerefox reads `.env`. Production lives at
60
+ `~/.cerefox/.env` and is never consulted when the override is set.
61
+
62
+ ```bash
63
+ mkdir -p ~/.cerefox/staging && chmod 700 ~/.cerefox/staging
64
+ ```
65
+
66
+ Then either run the interactive setup against it:
67
+
68
+ ```bash
69
+ CEREFOX_CONFIG_DIR=~/.cerefox/staging cerefox init
70
+ ```
71
+
72
+ …or write `~/.cerefox/staging/.env` (mode 0600) directly:
73
+
74
+ ```bash
75
+ CEREFOX_ENV_LABEL=staging
76
+ CEREFOX_SUPABASE_URL=https://<staging-ref>.supabase.co
77
+ CEREFOX_SUPABASE_KEY=sb_secret_… # staging project's secret key
78
+ CEREFOX_DATABASE_URL=postgresql://postgres.<staging-ref>:…@aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require
79
+
80
+ # Isolate snapshots. CEREFOX_BACKUP_DIR does NOT follow the config dir, so
81
+ # without this line staging backups land beside production's.
82
+ # Use an ABSOLUTE path: a relative value resolves against the working
83
+ # directory, so snapshots scatter wherever you happen to run the command.
84
+ CEREFOX_BACKUP_DIR=~/.cerefox/staging/backups
85
+
86
+ OPENAI_API_KEY=sk-…
87
+ SUPABASE_ACCESS_TOKEN=sbp_… # account-level; same as prod
88
+ ```
89
+
90
+ > **Snapshot isolation needs v1.1.0-beta.3 or later.** On **beta.2 and
91
+ > earlier**, `backup create` read `CEREFOX_BACKUP_DIR` *before* loading the
92
+ > `.env` file, so the setting above was silently ignored and staging snapshots
93
+ > landed in production's directory. Until staging is on a build with the fix,
94
+ > pass the destination explicitly: `cfx-stg backup create --output-dir
95
+ > ~/.cerefox/staging/backups`.
96
+
97
+ **Mirror production's tuning.** Chunking and embedder settings still live in
98
+ `.env` (`CEREFOX_MAX_CHUNK_CHARS`, `CEREFOX_MIN_CHUNK_CHARS`, `CEREFOX_EMBEDDER`);
99
+ retrieval and retention moved into the database in v1.1.0, so mirror those with
100
+ `cerefox config set` against staging (or the Settings page).
101
+ A staging result only means something if the knobs match; different chunk sizes
102
+ make every comparison noise. **Do not** copy credentials — staging has its own.
103
+
104
+ ---
105
+
106
+ ## 3. Pin a Cerefox version for staging
107
+
108
+ `CEREFOX_CONFIG_DIR` switches the *database*, not the *code*. The `cerefox` on
109
+ your PATH is a single global npm install, so on its own it would point both
110
+ environments at the same version — which defeats the main purpose of staging:
111
+ rehearsing a **pre-release** build before production ever sees it.
112
+
113
+ Give staging its own install tree. npm's `--prefix` keeps it entirely separate
114
+ from the global one, so production's binary is never touched:
115
+
116
+ ```bash
117
+ # Rehearsing a pre-release (the usual case):
118
+ npm install -g --prefix ~/.cerefox/staging/cli @cerefox/memory@beta
119
+
120
+ # Rehearsing a NORMAL release, where no beta was cut: pin the version
121
+ # explicitly. A bare `@cerefox/memory` resolves `latest` at install time, so
122
+ # staging silently records nothing about what it is running — and running it
123
+ # before the publish completes would install the PREVIOUS version, which is the
124
+ # one thing staging exists to avoid.
125
+ npm install -g --prefix ~/.cerefox/staging/cli @cerefox/memory@1.4.0
126
+ ```
127
+
128
+ Then bind **both axes — version and environment — in a single alias**, so they
129
+ can never drift apart:
130
+
131
+ ```bash
132
+ alias cfx-stg='CEREFOX_CONFIG_DIR=~/.cerefox/staging ~/.cerefox/staging/cli/bin/cerefox'
133
+ ```
134
+
135
+ Put it in `~/.zshrc` (or `~/.bashrc`) and reload. From here on, `cerefox` means
136
+ production-version-on-production-data and `cfx-stg` means
137
+ staging-version-on-staging-data. There is no combination of the two that a typo
138
+ can produce.
139
+
140
+ > **The alias is the protection — scripts and agents that bypass it lose it.**
141
+ > `CEREFOX_CONFIG_DIR=~/.cerefox/staging cerefox …` (bare binary, staging
142
+ > config) recombines the axes: production *code* on staging *data*. Aliases
143
+ > don't exist in non-interactive shells, which is exactly where automation
144
+ > runs, so spell out the pinned binary path there. And remember the global
145
+ > binary is itself a production component: `cerefox self-update` replaces it
146
+ > no matter which `CEREFOX_CONFIG_DIR` is set — updating "for staging" that
147
+ > way is a production change.
148
+
149
+ Verify the split before trusting it:
150
+
151
+ ```bash
152
+ cerefox --version # production, e.g. 1.0.8
153
+ cfx-stg --version # staging, e.g. 1.1.0-beta.2
154
+ ```
155
+
156
+ To move staging to a newer pre-release later, re-run the `npm install` above;
157
+ production is unaffected. If you'd rather not keep an install tree at all,
158
+ `npx --package=@cerefox/memory@beta cerefox …` works too, but it re-resolves the
159
+ package on every call and makes the version harder to pin down when something
160
+ misbehaves.
161
+
162
+ ---
163
+
164
+ ## 4. Deploy and verify
165
+
166
+ ```bash
167
+ cfx-stg server deploy # fresh database → schema + RPCs + 9 Edge Functions
168
+ cfx-stg doctor
169
+ ```
170
+
171
+ `doctor` should report the staging config path and URL. Two lines are expected
172
+ on a fresh project:
173
+
174
+ - `ℹ edge functions … No CEREFOX_ACCESS_TOKEN set` — staging has no Cerefox
175
+ access token yet. Run `cfx-stg token generate` if you plan to test the Edge
176
+ Function / remote-MCP path there.
177
+ - `✓ content format no documents yet` — nothing imported.
178
+
179
+ **Checking database/schema state.** There is no `cerefox db status` command.
180
+ Use one of:
181
+
182
+ | Want | Command |
183
+ |---|---|
184
+ | Deployed schema version, reachability, drift banner | `cfx-stg doctor` |
185
+ | What a deploy *would* do, without doing it | `cfx-stg server deploy --dry-run` |
186
+ | Per-migration applied/pending list | `bun scripts/db_migrate.ts --status` (repo clone; contributor-only) |
187
+
188
+ `doctor` is the one to reach for; the migration list is only interesting when a
189
+ deploy behaved unexpectedly.
190
+
191
+ > **Contributor scripts and a repo `.env`.** The `bun scripts/*.ts` tools honour
192
+ > `CEREFOX_CONFIG_DIR` — but only from the version that fixed this. Bun
193
+ > auto-loads `.env` from the working directory, so on **v1.1.0-beta.1 and
194
+ > earlier** a repo clone with its own `.env` silently outranked the config dir:
195
+ > `CEREFOX_CONFIG_DIR=…/staging bun scripts/db_migrate.ts --status` reported
196
+ > *production*. If you're on an older build, run those scripts from a directory
197
+ > with no `.env`, and confirm the target before trusting the output.
198
+
199
+ ---
200
+
201
+ ## 5. Populate from a production snapshot
202
+
203
+ ```bash
204
+ cerefox backup create # production
205
+ cfx-stg backup restore ~/.cerefox/backups/<snapshot>.json
206
+ ```
207
+
208
+ Backups carry documents, chunks, projects, memberships and (from v1.1.0)
209
+ relations and lifecycle status. Restore is idempotent — re-running it is safe
210
+ and converges on the same state rather than duplicating anything.
211
+
212
+ Restoring an **older** snapshot into a **newer** schema works — new columns take
213
+ their defaults. The reverse is not supported.
214
+
215
+ Two count details that look like bugs and are not:
216
+
217
+ - **Trashed documents are not carried over.** `backup create` captures live
218
+ documents only (`deleted_at IS NULL`), so anything in production's trash is
219
+ absent from staging. Nothing in the trash is lost *in production* — it just
220
+ isn't part of the snapshot.
221
+ - **A membership shortfall on pre-v1.1.0 snapshots.** Older `backup create`
222
+ captured the document↔project junction unfiltered, including rows belonging
223
+ to trashed documents. Restore drops those (their document isn't in the file),
224
+ so the summary reports fewer memberships than the header claims — 362 of 369
225
+ on the maintainer's store. From v1.1.0 the capture filters them out, and the
226
+ two numbers agree.
227
+
228
+ ---
229
+
230
+ ## 6. Run both web servers at once
231
+
232
+ The daemon's pidfile and log follow `CEREFOX_CONFIG_DIR`, so staging writes to
233
+ `~/.cerefox/staging/web.{pid,log}` and production to `~/.cerefox/web.{pid,log}`.
234
+ Each `web stop` / `web status` acts only on its own environment.
235
+
236
+ > **Requires v1.1.0-beta.2 or later.** On **beta.1 and earlier** both
237
+ > environments shared `~/.cerefox/web.pid`, so `cfx-stg web start` refuses with
238
+ > *"A Cerefox web daemon is already running on :8000"* — it is reading
239
+ > production's pidfile. Until staging is on a build with the fix, start it in
240
+ > the **foreground** instead, which never touches the pidfile:
241
+ >
242
+ > ```bash
243
+ > cfx-stg web --port 8030 # no `start` subcommand; Ctrl-C to stop
244
+ > ```
245
+
246
+ Pick a different port for staging so the two can run simultaneously:
247
+
248
+ ```bash
249
+ cfx-stg web start --port 8010
250
+ cfx-stg web status # staging only
251
+ cerefox web status # production only — unaffected
252
+ ```
253
+
254
+ Set `CEREFOX_ENV_LABEL=staging` in the staging `.env` (Step 2) and the
255
+ environment names itself everywhere it matters — two tabs that look identical
256
+ otherwise:
257
+
258
+ | Surface | With the label set |
259
+ |---|---|
260
+ | Web UI | A banner on every page: *"STAGING environment — not production."* |
261
+ | `doctor` | Title line reads `Cerefox doctor [STAGING]` |
262
+ | `backup create` | Filename becomes `cerefox-staging-<stamp>.json`, and the label is stored in the payload |
263
+ | `backup restore` | Warns when the snapshot's environment differs from the target's |
264
+
265
+ The filename and restore warning matter because `CEREFOX_BACKUP_DIR` does not
266
+ follow `CEREFOX_CONFIG_DIR`: staging and production snapshots can end up in one
267
+ directory, and a restore that picks "the most recent file" there would
268
+ otherwise seed production from staging without saying so.
269
+
270
+ **Requires v1.1.0-beta.3 or later** — on earlier builds `CEREFOX_ENV_LABEL` is
271
+ read but nothing acts on it.
272
+
273
+ ---
274
+
275
+ ## Known limits
276
+
277
+ | Area | Problem |
278
+ |---|---|
279
+ | **Agent (MCP) config** | Safe since v1.4.0 ([#168](https://github.com/fstamatelopoulos/cerefox/issues/168)). `configure-agent` names the server after `CEREFOX_ENV_LABEL`, so a staging environment registers as **`cerefox-staging`** alongside your production `cerefox` entry rather than replacing it, and an agent can hold both. The labelled entry also carries its own `CEREFOX_CONFIG_DIR` and `CEREFOX_ENV_LABEL` in the config it writes — without that the client would spawn the server with *its own* environment (a GUI client launched from the dock has none), `CEREFOX_CONFIG_DIR` would be absent, and an entry named `cerefox-staging` would quietly serve production. Before v1.4.0 it registered every environment as `cerefox` and running it from staging silently repointed all your agents. |
280
+ | **`doctor`'s `mcp clients` line** | It inspects your global agent configs, which point at production, and reports them even in staging mode. Informative, but easy to misread as "staging is wired to my agents". |
281
+ | **`doctor` remediation commands** | Environment-aware since v1.8.0: in a staging environment the remediations tell you to prefix `CEREFOX_CONFIG_DIR` (or use the alias). Before that, a staging `doctor` printed bare `cerefox …` remediations that act on production. |
282
+
283
+ Everything else — config, database, backups, CLI version, web daemon — is
284
+ separated and validated.
285
+
286
+ ### What is *not* isolated, by design
287
+
288
+ Two things are shared on purpose, and both are safe:
289
+
290
+ - **`SUPABASE_ACCESS_TOKEN`** is an account-level credential, not a
291
+ project-level one. The same value belongs in both `.env` files; the project
292
+ it acts on comes from the URL and database URL beside it.
293
+ - **Your OpenAI key.** Staging embeds against the same account, so staging
294
+ ingestion and `migrate-format` rehearsals cost real money. That is the point —
295
+ it is how you measure the spend before committing production to it.
296
+
297
+ ---
298
+
299
+ ## Housekeeping
300
+
301
+ Pause the staging project in the Supabase dashboard between test rounds — a
302
+ paused project keeps its data without consuming free-tier compute. Check your
303
+ plan's limit on simultaneously active projects before creating the second one.
304
+
305
+ ## Pause it when you are not using it
306
+
307
+ A Supabase project on the free tier costs nothing while paused, and leaving a
308
+ staging environment running between bursts of work is pure waste. Pause it from
309
+ the Supabase dashboard when you finish, and unpause it when you start.
310
+
311
+ Two things follow from that:
312
+
313
+ - **Give it a minute after unpausing.** The first queries against a
314
+ just-resumed project are slow while the instance wakes.
315
+ - **A paused project does not announce itself.** Commands hang or fail with
316
+ connection and timeout errors, and `cerefox doctor` reports the Data API as
317
+ unreachable. That looks identical to a broken deployment or a bad credential.
318
+ Check whether the project is paused before diagnosing anything else.
319
+
320
+ ## Running the test suites against staging
321
+
322
+ The package suite's live tests write real documents. They resolve credentials
323
+ exactly as the CLI does, so a bare `bun test` on a maintainer's machine targets
324
+ **production** — which is how a run once left ~79 audit-log entries there. Since
325
+ v1.4.0 those suites **skip unless the target carries `CEREFOX_ENV_LABEL`**, so
326
+ point them at staging explicitly:
327
+
328
+ ```bash
329
+ CEREFOX_CONFIG_DIR=~/.cerefox/staging bun test
330
+ ```
331
+
332
+ `CEREFOX_ALLOW_PROD_WRITE_TESTS=1` overrides the guard, for the rare case where
333
+ production really is the intended target. Pointing every *command* at staging is
334
+ not enough: the test runner is a separate process with its own resolution.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerefox/memory",
3
- "version": "1.15.2",
3
+ "version": "1.15.3",
4
4
  "description": "Cerefox \u2014 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",