@cerefox/memory 0.9.11 → 0.10.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.
@@ -15,7 +15,7 @@
15
15
  href="https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&display=swap"
16
16
  />
17
17
  <title>Cerefox</title>
18
- <script type="module" crossorigin src="/app/assets/index-AFUS7_0T.js"></script>
18
+ <script type="module" crossorigin src="/app/assets/index-DVXDQ7__.js"></script>
19
19
  <link rel="stylesheet" crossorigin href="/app/assets/index-Asx5wD7g.css">
20
20
  </head>
21
21
  <body>
@@ -18,7 +18,7 @@
18
18
  * doesn't touch `supabase/functions/` leaves it alone).
19
19
  */
20
20
 
21
- export const EF_VERSION = "0.9.3";
21
+ export const EF_VERSION = "0.10.1";
22
22
 
23
23
  /**
24
24
  * The 8 peer EFs the cerefox-mcp aggregator probes (excludes cerefox-mcp
@@ -17,25 +17,52 @@ export const OPENAI_EMBEDDING_URL = "https://api.openai.com/v1/embeddings";
17
17
  export const OPENAI_MODEL = "text-embedding-3-small";
18
18
  export const EMBEDDING_DIMENSIONS = 768;
19
19
 
20
+ /**
21
+ * Resolve the OpenAI embedding endpoint/model/dimensions, applying `.env`
22
+ * overrides over the built-in defaults. These were configurable in the Python
23
+ * runtime; the TS migration hardcoded them.
24
+ *
25
+ * ⚠ Overriding the MODEL or DIMENSIONS is a BREAKING change: query vectors must
26
+ * match the stored vectors and the DB column is `vector(768)`. Changing either
27
+ * requires re-embedding the whole corpus (`cerefox server reindex`) and, for a
28
+ * non-768 model, a schema change. `CEREFOX_OPENAI_BASE_URL` (proxy/gateway) is
29
+ * the only safe one to flip on an existing KB.
30
+ *
31
+ * Runtime-agnostic env read; the Deno Edge Function (no host env) keeps the
32
+ * constants — matching the EF's "model config is a constant" design.
33
+ */
34
+ export function openaiEmbeddingConfig(): { url: string; model: string; dimensions: number } {
35
+ const env =
36
+ (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env ?? {};
37
+ const base = env.CEREFOX_OPENAI_BASE_URL?.replace(/\/+$/, "");
38
+ const dims = Number.parseInt(env.CEREFOX_OPENAI_EMBEDDING_DIMENSIONS ?? "", 10);
39
+ return {
40
+ url: base ? `${base}/embeddings` : OPENAI_EMBEDDING_URL,
41
+ model: env.CEREFOX_OPENAI_EMBEDDING_MODEL || OPENAI_MODEL,
42
+ dimensions: Number.isNaN(dims) || dims <= 0 ? EMBEDDING_DIMENSIONS : dims,
43
+ };
44
+ }
45
+
20
46
  const EMBEDDING_MAX_RETRIES = 3;
21
47
  const EMBEDDING_INITIAL_BACKOFF_MS = 500; // 500ms → 1s → 2s
22
48
 
23
49
  /** Embed a single string. Used for the query vector in `cerefox_search`. */
24
50
  export async function getEmbedding(text: string, apiKey: string): Promise<number[]> {
25
51
  let lastError: Error | null = null;
52
+ const cfg = openaiEmbeddingConfig();
26
53
 
27
54
  for (let attempt = 0; attempt < EMBEDDING_MAX_RETRIES; attempt++) {
28
55
  try {
29
- const response = await fetch(OPENAI_EMBEDDING_URL, {
56
+ const response = await fetch(cfg.url, {
30
57
  method: "POST",
31
58
  headers: {
32
59
  "Authorization": `Bearer ${apiKey}`,
33
60
  "Content-Type": "application/json",
34
61
  },
35
62
  body: JSON.stringify({
36
- model: OPENAI_MODEL,
63
+ model: cfg.model,
37
64
  input: text,
38
- dimensions: EMBEDDING_DIMENSIONS,
65
+ dimensions: cfg.dimensions,
39
66
  }),
40
67
  });
41
68
 
@@ -93,19 +120,20 @@ async function embedBatchSingleCall(
93
120
  apiKey: string,
94
121
  ): Promise<number[][]> {
95
122
  let lastError: Error | null = null;
123
+ const cfg = openaiEmbeddingConfig();
96
124
 
97
125
  for (let attempt = 0; attempt < EMBEDDING_MAX_RETRIES; attempt++) {
98
126
  try {
99
- const response = await fetch(OPENAI_EMBEDDING_URL, {
127
+ const response = await fetch(cfg.url, {
100
128
  method: "POST",
101
129
  headers: {
102
130
  "Authorization": `Bearer ${apiKey}`,
103
131
  "Content-Type": "application/json",
104
132
  },
105
133
  body: JSON.stringify({
106
- model: OPENAI_MODEL,
134
+ model: cfg.model,
107
135
  input: texts,
108
- dimensions: EMBEDDING_DIMENSIONS,
136
+ dimensions: cfg.dimensions,
109
137
  }),
110
138
  });
111
139
 
@@ -14,10 +14,46 @@
14
14
 
15
15
  import type { MCPSupabaseClient } from "./types.ts";
16
16
 
17
- /** Server-enforced response-size ceiling for MCP results. Agents can request
18
- * smaller budgets via `max_bytes`; values above this are capped. */
17
+ /** Built-in default response-size ceiling for MCP/EF results. */
19
18
  export const MAX_RESPONSE_BYTES = 200_000;
20
19
 
20
+ /**
21
+ * Server-enforced response-size ceiling for MCP/Edge-Function results (agents
22
+ * can request smaller via `max_bytes`; larger is capped). Overridable via
23
+ * `CEREFOX_MAX_RESPONSE_BYTES`. Read by the Python runtime; restored after the
24
+ * TS migration. The web UI + CLI are intentionally unlimited and do not use this.
25
+ * Runtime-agnostic env read (Deno EF safely falls back to the default).
26
+ */
27
+ export function getMaxResponseBytes(): number {
28
+ const raw = (globalThis as { process?: { env?: Record<string, string | undefined> } })
29
+ .process?.env?.CEREFOX_MAX_RESPONSE_BYTES;
30
+ if (raw === undefined || raw === "") return MAX_RESPONSE_BYTES;
31
+ const n = Number.parseInt(raw, 10);
32
+ return Number.isNaN(n) || n <= 0 ? MAX_RESPONSE_BYTES : n;
33
+ }
34
+
35
+ /** Built-in default cosine-similarity floor for hybrid/semantic search. */
36
+ export const DEFAULT_MIN_SEARCH_SCORE = 0.5;
37
+
38
+ /**
39
+ * Resolve the minimum cosine-similarity floor for hybrid/semantic search
40
+ * (vector-only matches below this are dropped; FTS matches always pass).
41
+ * Overridable via the `CEREFOX_MIN_SEARCH_SCORE` env var (0.0–1.0). The Python
42
+ * runtime read this; the TS migration dropped it — restored here as the single
43
+ * default used by the CLI, local/remote MCP, and the web API.
44
+ *
45
+ * Runtime-agnostic env read: works in Node/Bun; in the Deno Edge Function
46
+ * `process` may be absent, so it falls back to the built-in default (the cloud
47
+ * EF path doesn't use the host `.env` anyway).
48
+ */
49
+ export function getMinSearchScore(): number {
50
+ const raw = (globalThis as { process?: { env?: Record<string, string | undefined> } })
51
+ .process?.env?.CEREFOX_MIN_SEARCH_SCORE;
52
+ if (raw === undefined || raw === "") return DEFAULT_MIN_SEARCH_SCORE;
53
+ const n = Number.parseFloat(raw);
54
+ return Number.isNaN(n) || n < 0 || n > 1 ? DEFAULT_MIN_SEARCH_SCORE : n;
55
+ }
56
+
21
57
  export function applyByteBudget(
22
58
  rows: unknown[],
23
59
  maxBytes: number,
@@ -7,7 +7,7 @@
7
7
 
8
8
  import type { MCPSupabaseClient } from "./types.ts";
9
9
 
10
- import { applyByteBudget, logUsage, MAX_RESPONSE_BYTES } from "./_utils.ts";
10
+ import { applyByteBudget, getMaxResponseBytes, logUsage } from "./_utils.ts";
11
11
  import { lookupProjectId } from "./_projects.ts";
12
12
  import { McpInvalidParams, type ToolContext, type ToolDefinition } from "./types.ts";
13
13
 
@@ -39,8 +39,9 @@ async function handler(
39
39
  }
40
40
 
41
41
  // Enforce byte ceiling for content mode
42
+ const ceiling = getMaxResponseBytes();
42
43
  const max_bytes = include_content
43
- ? Math.min(requested_max_bytes ?? MAX_RESPONSE_BYTES, MAX_RESPONSE_BYTES)
44
+ ? Math.min(requested_max_bytes ?? ceiling, ceiling)
44
45
  : null;
45
46
 
46
47
  const params: Record<string, unknown> = {
@@ -18,7 +18,7 @@
18
18
  import type { MCPSupabaseClient } from "./types.ts";
19
19
 
20
20
  import { getEmbedding } from "../embeddings/index.ts";
21
- import { applyByteBudget, logUsage, MAX_RESPONSE_BYTES } from "./_utils.ts";
21
+ import { applyByteBudget, getMaxResponseBytes, getMinSearchScore, logUsage } from "./_utils.ts";
22
22
  import { lookupProjectId } from "./_projects.ts";
23
23
  import { McpInvalidParams, type ToolContext, type ToolDefinition } from "./types.ts";
24
24
 
@@ -32,12 +32,13 @@ async function handler(
32
32
  const match_count = (args.match_count as number | undefined) ?? 5;
33
33
  const mode = (args.mode as string | undefined) ?? "docs";
34
34
  const alpha = (args.alpha as number | undefined) ?? 0.7;
35
- const min_score = (args.min_score as number | undefined) ?? 0.5;
35
+ const min_score = (args.min_score as number | undefined) ?? getMinSearchScore();
36
36
  const metadata_filter =
37
37
  (args.metadata_filter as Record<string, string> | null | undefined) ?? null;
38
38
  const requested_max_bytes = args.max_bytes as number | undefined;
39
39
 
40
- const max_bytes = Math.min(requested_max_bytes ?? MAX_RESPONSE_BYTES, MAX_RESPONSE_BYTES);
40
+ const ceiling = getMaxResponseBytes();
41
+ const max_bytes = Math.min(requested_max_bytes ?? ceiling, ceiling);
41
42
 
42
43
  if (
43
44
  metadata_filter !== null &&
@@ -14,7 +14,7 @@ Every command reads configuration from `.env` in the working directory (or envir
14
14
 
15
15
  The CLI is the TypeScript `@cerefox/memory` package. Invoke any command as plain `cerefox <subcommand>` (installed via the installer or `npm install -g @cerefox/memory` — see [`quickstart.md`](quickstart.md#1-install)).
16
16
 
17
- > **v0.9 verb rename**: commands now follow a `resource verb` shape (e.g. `cerefox document get`, `cerefox project list`). The old flat verbs (`get-doc`, `list-docs`, `ingest`, `list-versions`, `config-get`, `deploy-server`, `docs`, …) are husks and have been removed — use the new forms below.
17
+ > **v0.9 verb rename**: commands now follow a `resource verb` shape (e.g. `cerefox document get`, `cerefox project list`). The old flat verbs (`get-doc`, `list-docs`, `ingest`, `list-versions`, `config-get`, `deploy-server`, `docs`, …) survive as hidden husks — they still run but print a pointer to the new form and exit non-zero (removed only at v1.0). Use the new forms below.
18
18
 
19
19
  ## Commands
20
20
 
@@ -141,7 +141,7 @@ cerefox search [OPTIONS] QUERY
141
141
  ```bash
142
142
  cerefox search "OAuth design"
143
143
  cerefox search "decisions" --metadata-filter '{"type":"decision-log"}' --match-count 5
144
- cerefox search "what we tried" --mode semantic --requestor "claude-code"
144
+ cerefox search "what we tried" --mode hybrid --requestor "claude-code"
145
145
  cerefox search "design docs" --only-metadata
146
146
  ```
147
147
 
@@ -24,6 +24,13 @@ CEREFOX_CONFIG_DIR=~/.cerefox-personal cerefox search "…"
24
24
 
25
25
  Full rule documented in [`docs/specs/polish-and-distribution-design.md` §7](../specs/polish-and-distribution-design.md).
26
26
 
27
+ > **Local / self-hosted (World B).** For the Docker backend (`cerefox-local`), do **not**
28
+ > set the Supabase or `CEREFOX_DATABASE_URL` vars below — the container generates and owns
29
+ > them. Put `OPENAI_API_KEY` plus any of the `CEREFOX_*` **tuning** options on this page
30
+ > (search, chunking, retrieval, versioning, embedding base-url/model, caller identity) in
31
+ > `~/.cerefox/local/.env`; the installer + `cerefox-local` forward them into the container.
32
+ > Apply changes with `cerefox-local init`. See [`setup-local.md`](setup-local.md).
33
+
27
34
  ---
28
35
 
29
36
  ## Supabase / Database
@@ -45,34 +52,27 @@ Full rule documented in [`docs/specs/polish-and-distribution-design.md` §7](../
45
52
 
46
53
  Cerefox uses cloud-based embedding APIs. Local models (mpnet, Ollama) are not supported — they require large downloads, fail on some hardware, and add installation complexity.
47
54
 
48
- | Variable | Default | Description |
49
- |----------|---------|-------------|
50
- | `CEREFOX_EMBEDDER` | `openai` | Embedding provider. Valid values: `openai`, `fireworks` |
55
+ > **TS runtime: OpenAI only (today).** The current TypeScript runtime implements the
56
+ > OpenAI embedder. `CEREFOX_EMBEDDER` and the `CEREFOX_FIREWORKS_*` variables are
57
+ > documented (they worked in the retired Python runtime) but are **not yet wired in TS** —
58
+ > they're currently no-ops, tracked for a future release.
51
59
 
52
60
  ### OpenAI (default, recommended)
53
61
 
54
62
  | Variable | Default | Description |
55
63
  |----------|---------|-------------|
56
64
  | `OPENAI_API_KEY` | `""` | OpenAI API key. Also accepted as `CEREFOX_OPENAI_API_KEY`. Get one at [platform.openai.com/api-keys](https://platform.openai.com/api-keys). |
57
- | `CEREFOX_OPENAI_BASE_URL` | `https://api.openai.com/v1` | API base URL. Override for proxies or OpenAI-compatible providers. |
58
- | `CEREFOX_OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` | OpenAI embedding model. |
59
- | `CEREFOX_OPENAI_EMBEDDING_DIMENSIONS` | `768` | Output dimensions. Must match the database schema (VECTOR(768)). |
60
-
61
- For cost estimates see `docs/guides/operational-cost.md`.
62
-
63
- ### Fireworks AI (alternative, lower cost)
65
+ | `CEREFOX_OPENAI_BASE_URL` | `https://api.openai.com/v1` | API base URL. Safe to override for proxies or OpenAI-compatible gateways. |
66
+ | `CEREFOX_OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` | OpenAI embedding model. ⚠ see warning below. |
67
+ | `CEREFOX_OPENAI_EMBEDDING_DIMENSIONS` | `768` | Output dimensions. Must match the DB schema (`VECTOR(768)`). ⚠ see warning below. |
64
68
 
65
- | Variable | Default | Description |
66
- |----------|---------|-------------|
67
- | `CEREFOX_FIREWORKS_API_KEY` | `""` | Fireworks AI API key. |
68
- | `CEREFOX_FIREWORKS_BASE_URL` | `https://api.fireworks.ai/inference/v1` | Fireworks API base URL. |
69
- | `CEREFOX_FIREWORKS_EMBEDDING_MODEL` | `nomic-ai/nomic-embed-text-v1.5` | Fireworks model. Must natively output 768-dim vectors. |
69
+ > **⚠ Changing the model or dimensions is breaking.** Query vectors must match the stored
70
+ > vectors. After changing `CEREFOX_OPENAI_EMBEDDING_MODEL` you MUST re-embed the whole
71
+ > corpus (`cerefox server reindex`); changing `CEREFOX_OPENAI_EMBEDDING_DIMENSIONS` away
72
+ > from 768 also requires a schema change. `CEREFOX_OPENAI_BASE_URL` is the only one safe to
73
+ > flip on an existing knowledge base.
70
74
 
71
- To use Fireworks:
72
- ```env
73
- CEREFOX_EMBEDDER=fireworks
74
- CEREFOX_FIREWORKS_API_KEY=fw_...
75
- ```
75
+ For cost estimates see `docs/guides/operational-cost.md`.
76
76
 
77
77
  ### Edge Functions (for agents)
78
78
 
@@ -37,7 +37,7 @@ jobs / CI / make targets that invoke them.
37
37
 
38
38
  ### TS scripts and `.env` resolution
39
39
 
40
- `bun scripts/<name>.ts` reads the same `.env` the Python CLI does. Precedence:
40
+ `bun scripts/<name>.ts` reads the same `.env` the `cerefox` CLI does. Precedence:
41
41
 
42
42
  1. `CEREFOX_CONFIG_DIR` env var (explicit override; supports `~`).
43
43
  2. `./.env` in the current working directory (dev mode).
@@ -1,13 +1,18 @@
1
1
  # Quickstart -- Zero to First Document
2
2
 
3
- Get Cerefox running on your machine via the npm install path. **No source
4
- clone, no Python required.** Once you have a Supabase project (the one
5
- prerequisite — provisioning a free one takes a few minutes), the Cerefox
6
- install and setup below is about 5 minutes.
3
+ Get Cerefox running on your machine via the npm install path (the **cloud /
4
+ Supabase** backend). **No source clone required.** Once you have a Supabase
5
+ project (the one prerequisite — provisioning a free one takes a few minutes),
6
+ the Cerefox install and setup below takes ~15 minutes.
7
7
 
8
8
  > **Upgrading from an earlier version?** See [`upgrading.md`](upgrading.md)
9
9
  > for migration steps instead.
10
10
 
11
+ > **Want no cloud at all?** Cerefox also runs **fully local** — one Docker
12
+ > container, no Supabase account, no Node/Bun on the host. See
13
+ > [`setup-local.md`](setup-local.md). This quickstart covers the hosted-Supabase
14
+ > path.
15
+
11
16
  ---
12
17
 
13
18
  ## Prerequisites
@@ -109,8 +114,9 @@ You should see results from the bundled self-docs.
109
114
  The path above is for **end users** (no clone). If you want to hack on Cerefox,
110
115
  clone the repo, run `bun install`, and use the contributor scripts
111
116
  (`bun scripts/db_deploy.ts`, `bun scripts/db_migrate.ts`). `uv` is only needed
112
- for the legacy Python MCP fallback. See [`setup-local.md`](setup-local.md) and
113
- `CONTRIBUTING.md`.
117
+ for the legacy Python MCP fallback. See [`CONTRIBUTING.md`](../../CONTRIBUTING.md).
118
+ (Want a no-cloud install instead? That's the self-hosted Docker backend —
119
+ [`setup-local.md`](setup-local.md).)
114
120
 
115
121
  ---
116
122
 
@@ -120,7 +126,7 @@ for the legacy Python MCP fallback. See [`setup-local.md`](setup-local.md) and
120
126
  `cerefox document ingest-dir ./notes/` (recurses into sub-directories automatically)
121
127
  - **Search from the CLI**: `cerefox search "your query"`
122
128
  - **Discover all commands**: `cerefox --help`
123
- - **Run the web UI**: `cerefox web` (TypeScript — Hono backend + React SPA); see [`setup-local.md`](setup-local.md)
129
+ - **Run the web UI**: `cerefox web` (TypeScript — Hono backend + React SPA); see [`cli.md`](cli.md)
124
130
  - **Connect more AI clients** (Cursor, Codex, ChatGPT GPT Actions, etc.):
125
131
  [`connect-agents.md`](connect-agents.md)
126
132
  - **Configuration reference**: [`configuration.md`](configuration.md)
@@ -1,184 +1,149 @@
1
- # Local Setup Guide
1
+ # Local / Self-Hosted Setup (Docker)
2
2
 
3
- Run the Cerefox web server and database on your own machine using Docker for Postgres+pgvector. Embeddings use the OpenAI API — an `OPENAI_API_KEY` is required even for local setups.
3
+ Run Cerefox **fully on your own machine** — no hosted Supabase, no cloud database. One
4
+ Docker container bundles everything: Postgres + pgvector, the PostgREST Data API, and the
5
+ Cerefox web server. You get the same web UI, CLI, and MCP server as the cloud setup.
4
6
 
5
- This guide is aimed at **contributors** who want a fully local stack (no hosted Supabase). End users on a hosted Supabase project should follow [`quickstart.md`](quickstart.md) instead.
7
+ > **Embeddings still use the OpenAI API.** An `OPENAI_API_KEY` is required even for a
8
+ > local setup (the database and web server are local; embedding generation is not). A
9
+ > fully offline embedder is on the roadmap.
6
10
 
7
- ---
8
-
9
- ## Prerequisites
11
+ ## Cloud vs. Local — pick one
10
12
 
11
- - Docker and Docker Compose
12
- - **Node.js 20+** or **Bun 1.0+** (the CLI runtime)
13
- - An OpenAI API key (for embeddings — [platform.openai.com/api-keys](https://platform.openai.com/api-keys))
14
-
15
- > The Python implementation is legacy and slated for removal in a future release; only the Python MCP server remains as a fallback. `uv` is only needed if you intend to run that fallback (`uv run cerefox mcp`).
16
-
17
- ---
13
+ Cerefox has two independent "worlds". Most people run **one or the other**:
18
14
 
19
- ## Step 1 — Clone and install
15
+ | | Cloud / Supabase | **Local / self-hosted (this guide)** |
16
+ |---|---|---|
17
+ | Install | `curl … install.sh \| sh` (npm) | `curl … install-local.sh \| sh` (Docker) |
18
+ | Command | `cerefox` | `cerefox-local` |
19
+ | Backend | hosted Supabase | a Docker container on your machine |
20
+ | Host runtime | Node/Bun | **Docker only** |
20
21
 
21
- ```bash
22
- git clone https://github.com/fstamatelopoulos/cerefox.git
23
- cd cerefox
24
- bun install
25
- ```
22
+ The two never collide — different installer, different command name — so even if you run
23
+ both, your cloud `~/.cerefox/.env` is never touched by the local installer.
26
24
 
27
25
  ---
28
26
 
29
- ## Step 2 — Start Postgres with pgvector
30
-
31
- The included `docker-compose.yml` spins up a Postgres 16 instance with the pgvector extension pre-installed:
32
-
33
- ```bash
34
- docker compose up -d postgres
35
- ```
27
+ ## Prerequisites
36
28
 
37
- Default connection details (overridable in `.env`):
29
+ - **Docker** (Docker Desktop, or [Colima](https://github.com/abiosoft/colima): `colima start`).
30
+ - An **OpenAI API key** — [platform.openai.com/api-keys](https://platform.openai.com/api-keys).
38
31
 
39
- | Setting | Default |
40
- |---------|---------|
41
- | Host | `localhost` |
42
- | Port | `5432` |
43
- | User | `cerefox` |
44
- | Password | `cerefox` |
45
- | Database | `cerefox` |
32
+ That's it. No Node, Bun, Postgres, or repo clone needed.
46
33
 
47
34
  ---
48
35
 
49
- ## Step 3 — Create a `.env` file
36
+ ## Step 1 — Install
50
37
 
51
38
  ```bash
52
- cp .env.example .env
39
+ OPENAI_API_KEY=sk-... sh -c "$(curl -fsSL https://github.com/fstamatelopoulos/cerefox/releases/latest/download/install-local.sh)"
53
40
  ```
54
41
 
55
- Edit `.env` for local Docker:
42
+ This pulls the published multi-arch image (`amd64` + `arm64`), starts the container, and
43
+ installs a `cerefox-local` command (symlinked into `~/.local/bin`). Pick a different port
44
+ with `PORT=8017 …`.
56
45
 
57
- ```env
58
- # Local Postgres (Docker)
59
- CEREFOX_DATABASE_URL=postgresql://cerefox:cerefox@localhost:5432/cerefox
46
+ > If the installer warns that `~/.local/bin` isn't on your `PATH`, add it:
47
+ > ```bash
48
+ > echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
49
+ > ```
60
50
 
61
- # For local-only use, Supabase keys are not required.
62
- # The web UI and CLI will work without them if you skip the Supabase MCP integration.
63
- CEREFOX_SUPABASE_URL=
64
- CEREFOX_SUPABASE_KEY=
51
+ The web UI is now at **http://localhost:8000/app/** (or your chosen port).
65
52
 
66
- # OpenAI API key for embeddings (text-embedding-3-small)
67
- OPENAI_API_KEY=sk-...
68
- ```
53
+ **How the credential works:** the container generates its own JWT secret on first boot and
54
+ mints the access token internally — the token never leaves the container. The only secret
55
+ stored on your host is `OPENAI_API_KEY` (in `~/.cerefox/local/.env`), so `upgrade` can
56
+ re-supply it.
69
57
 
70
58
  ---
71
59
 
72
- ## Step 4 — Deploy the schema
73
-
74
- ```bash
75
- bun scripts/db_deploy.ts
76
- ```
77
-
78
- This creates all tables, indexes, and RPC functions. Run with `--dry-run` to preview SQL without executing.
60
+ ## Step 2 — Use the CLI
79
61
 
80
- To start fresh:
62
+ `cerefox-local` runs the same commands as the cloud `cerefox`, but against your local
63
+ container:
81
64
 
82
65
  ```bash
83
- bun scripts/db_deploy.ts --reset # drops all cerefox_ tables first (typed-`yes` guard)
66
+ cerefox-local status # is it running? what URL?
67
+ cerefox-local document ingest my-notes.md --project-name personal
68
+ cerefox-local search "what did I write about planning?"
69
+ cerefox-local document list
84
70
  ```
85
71
 
86
- > End users on a hosted Supabase project use `cerefox server deploy` instead (no clone). The `bun scripts/db_*.ts` scripts are the low-level contributor path.
72
+ KB verbs (`search`, `document`, `project`, `metadata`, `audit`, `config`, `guides`, `mcp`)
73
+ run inside the container; lifecycle verbs run on the host (next section).
87
74
 
88
75
  ---
89
76
 
90
- ## Step 5 — Verify the setup
77
+ ## Step 3 — Connect an AI agent (MCP)
91
78
 
92
79
  ```bash
93
- bun scripts/db_migrate.ts --status
80
+ cerefox-local configure-agent
94
81
  ```
95
82
 
96
- You should see the schema reported as up to date with all migrations applied.
83
+ If the `claude` CLI is present this registers an MCP server named `cerefox-local` with
84
+ Claude Code automatically. Otherwise it prints the snippet to add to your client — the MCP
85
+ command is simply `cerefox-local mcp` (stdio), which the client launches per session. The
86
+ client never needs a token; the container holds it.
97
87
 
98
88
  ---
99
89
 
100
- ## Step 6 — Ingest your first document
101
-
102
- ```bash
103
- # Ingest a markdown file
104
- cerefox document ingest my-notes.md --project-name "personal"
105
-
106
- # Or paste content from stdin
107
- echo "# Quick Note\n\nThis is a quick note." | cerefox document ingest --paste --title "Quick Note"
108
- ```
109
-
110
- Each ingest calls the OpenAI embedding API once per batch of chunks (fast, typically under a second).
90
+ ## Managing the container
111
91
 
112
- ---
113
-
114
- ## Step 7 — Start the web UI
92
+ All host-side, via `cerefox-local`:
115
93
 
116
94
  ```bash
117
- cerefox web
95
+ cerefox-local start # start a stopped container
96
+ cerefox-local stop # stop it (your data persists in the Docker volume)
97
+ cerefox-local restart
98
+ cerefox-local logs -f # follow the logs
99
+ cerefox-local upgrade # pull the latest image + recreate (keeps data + OPENAI key)
100
+ cerefox-local uninstall # remove the container, KEEP the data volume
101
+ cerefox-local uninstall --purge # remove the container AND delete the data volume
118
102
  ```
119
103
 
120
- Open [http://localhost:8000](http://localhost:8000) in your browser.
121
-
122
- For development with auto-reload:
123
-
124
- ```bash
125
- cerefox web --reload
126
- ```
104
+ `upgrade` is the single update path: it pulls the newest image, recreates the container,
105
+ and refreshes the `cerefox-local` script itself. Because the CLI, web server, PostgREST,
106
+ and database schema all ship together in one versioned image, they never drift out of
107
+ sync.
127
108
 
128
109
  ---
129
110
 
130
- ## Step 8 — Search from the CLI
111
+ ## Where things live
131
112
 
132
- ```bash
133
- # Hybrid search (recommended)
134
- cerefox search "what did I write about project planning?"
135
-
136
- # Keyword-only search
137
- cerefox search "meeting notes" --mode fts
138
-
139
- # Semantic search
140
- cerefox search "ideas about creativity" --mode semantic
141
- ```
113
+ | Thing | Location |
114
+ |---|---|
115
+ | Container | name `cerefox-local` (override: `CEREFOX_LOCAL_CONTAINER`) |
116
+ | Your data | Docker volume `cerefox_local_pgdata` (survives `stop`/`upgrade`) |
117
+ | Host config | `~/.cerefox/local/.env` (OPENAI key + port only — **no token**) |
118
+ | Host command | `~/.cerefox/local/cerefox-local`, symlinked to `~/.local/bin/cerefox-local` |
142
119
 
143
120
  ---
144
121
 
145
- ## Running everything at once
122
+ ## Troubleshooting
146
123
 
147
- The `docker-compose.yml` also includes a `cerefox` service that runs the web UI:
124
+ **`docker not found` / can't connect** — start Docker Desktop, or `colima start`.
148
125
 
149
- ```bash
150
- docker compose up -d
151
- ```
152
-
153
- Web UI will be at [http://localhost:8000](http://localhost:8000).
126
+ **`cerefox-local: command not found`** — `~/.local/bin` isn't on your `PATH` (see Step 1).
154
127
 
155
- ---
128
+ **`container 'cerefox-local' is not running`** — `cerefox-local start` (or `status` to
129
+ check). After a reboot the container may be stopped depending on your Docker settings.
156
130
 
157
- ## Stopping services
131
+ **Ingest/search fail with no embeddings** — `OPENAI_API_KEY` wasn't set at install time.
132
+ Re-run the installer with the key, or set it and `cerefox-local upgrade`.
158
133
 
159
- ```bash
160
- docker compose down # stop, keep data
161
- docker compose down -v # stop and delete database volume
162
- ```
134
+ **Port already in use** — re-install with a free port: `PORT=8017 sh -c "$(curl -fsSL …/install-local.sh)"`.
163
135
 
164
136
  ---
165
137
 
166
- ## Updating the schema
138
+ ## Contributor notes
167
139
 
168
- When a new version of Cerefox introduces schema changes, run:
140
+ To build + test the image from a checkout (instead of pulling ghcr):
169
141
 
170
142
  ```bash
171
- bun scripts/db_migrate.ts # --status to preview, --dry-run to see SQL
143
+ docker build -f docker/local/Dockerfile -t cerefox-local:dev .
144
+ CEREFOX_LOCAL_IMAGE=cerefox-local:dev sh docker/local/install-local.sh
172
145
  ```
173
146
 
174
- This applies incremental migrations without losing data. Always back up first (see `ops-scripts.md`). End users on a hosted Supabase project run `cerefox server deploy` instead.
175
-
176
- ---
177
-
178
- ## Troubleshooting
179
-
180
- **pgvector extension not found**
181
- Make sure you're using the `pgvector/pgvector:pg16` Docker image (included in `docker-compose.yml`). Raw Postgres images do not include pgvector.
182
-
183
- **"Supabase is not configured" error**
184
- The CLI and web UI show this error if `CEREFOX_SUPABASE_URL` / `CEREFOX_SUPABASE_KEY` are empty. For local Docker setups, the app uses the direct Postgres URL (`CEREFOX_DATABASE_URL`) for schema deployment but the Supabase client for queries. Set up a local Supabase instance or use the hosted free tier (see `setup-supabase.md`).
147
+ See [`docker/local/README.md`](../../docker/local/README.md) for the image internals
148
+ (s6-overlay supervision, the `/rest/v1` proxy, the pinned PostgREST version) and
149
+ `docs/research/local-cerefox-design.md` for the design of record.
@@ -47,7 +47,7 @@ You need three values from Supabase: a URL, an API key, and a direct Postgres co
47
47
 
48
48
  See the **[Supabase API keys (2026)](#supabase-api-keys-2026)** section near the end of this guide for the full picture. The short version:
49
49
 
50
- - For `CEREFOX_SUPABASE_KEY` (this guide, Python web app, CLI): use the new **secret key** (`sb_secret_…`) from **Project Settings → API Keys → Secret key**. The legacy `service_role` JWT also still works during the transition.
50
+ - For `CEREFOX_SUPABASE_KEY` (this guide, the web UI, and the CLI): use the new **secret key** (`sb_secret_…`) from **Project Settings → API Keys → Secret key**. The legacy `service_role` JWT also still works during the transition.
51
51
  - For `CEREFOX_SUPABASE_ANON_KEY` (only if you'll use Edge Functions / MCP / GPT Actions; not needed for this guide's deployment step): you must use the **legacy anon JWT** (`eyJ…`). The new `sb_publishable_…` key fails at the Edge Function gateway. See the reference section for why.
52
52
 
53
53
  Either way: keep this key secret — it bypasses Row Level Security and grants full database access.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerefox/memory",
3
- "version": "0.9.11",
3
+ "version": "0.10.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",