@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.
- package/dist/bin/cerefox.js +114 -21
- package/dist/frontend/assets/{index-AFUS7_0T.js → index-DVXDQ7__.js} +2 -2
- package/dist/frontend/assets/{index-AFUS7_0T.js.map → index-DVXDQ7__.js.map} +1 -1
- package/dist/frontend/index.html +1 -1
- package/dist/server-assets/_shared/ef-meta/index.ts +1 -1
- package/dist/server-assets/_shared/embeddings/index.ts +34 -6
- package/dist/server-assets/_shared/mcp-tools/_utils.ts +38 -2
- package/dist/server-assets/_shared/mcp-tools/metadata-search.ts +3 -2
- package/dist/server-assets/_shared/mcp-tools/search.ts +4 -3
- package/docs/guides/cli.md +2 -2
- package/docs/guides/configuration.md +20 -20
- package/docs/guides/ops-scripts.md +1 -1
- package/docs/guides/quickstart.md +13 -7
- package/docs/guides/setup-local.md +85 -120
- package/docs/guides/setup-supabase.md +1 -1
- package/package.json +1 -1
package/dist/frontend/index.html
CHANGED
|
@@ -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-
|
|
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>
|
|
@@ -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(
|
|
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:
|
|
63
|
+
model: cfg.model,
|
|
37
64
|
input: text,
|
|
38
|
-
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(
|
|
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:
|
|
134
|
+
model: cfg.model,
|
|
107
135
|
input: texts,
|
|
108
|
-
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
|
-
/**
|
|
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,
|
|
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 ??
|
|
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,
|
|
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) ??
|
|
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
|
|
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 &&
|
package/docs/guides/cli.md
CHANGED
|
@@ -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`, …)
|
|
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
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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.
|
|
58
|
-
| `CEREFOX_OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` | OpenAI embedding model. |
|
|
59
|
-
| `CEREFOX_OPENAI_EMBEDDING_DIMENSIONS` | `768` | Output dimensions. Must match the
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
4
|
-
|
|
5
|
-
prerequisite — provisioning a free one takes a few minutes),
|
|
6
|
-
install and setup below
|
|
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 [`
|
|
113
|
-
|
|
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 [`
|
|
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
|
|
1
|
+
# Local / Self-Hosted Setup (Docker)
|
|
2
2
|
|
|
3
|
-
Run
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
36
|
+
## Step 1 — Install
|
|
50
37
|
|
|
51
38
|
```bash
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
|
|
67
|
-
|
|
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
|
|
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
|
-
|
|
62
|
+
`cerefox-local` runs the same commands as the cloud `cerefox`, but against your local
|
|
63
|
+
container:
|
|
81
64
|
|
|
82
65
|
```bash
|
|
83
|
-
|
|
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
|
-
|
|
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
|
|
77
|
+
## Step 3 — Connect an AI agent (MCP)
|
|
91
78
|
|
|
92
79
|
```bash
|
|
93
|
-
|
|
80
|
+
cerefox-local configure-agent
|
|
94
81
|
```
|
|
95
82
|
|
|
96
|
-
|
|
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
|
-
##
|
|
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
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
##
|
|
111
|
+
## Where things live
|
|
131
112
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
cerefox
|
|
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
|
-
##
|
|
122
|
+
## Troubleshooting
|
|
146
123
|
|
|
147
|
-
|
|
124
|
+
**`docker not found` / can't connect** — start Docker Desktop, or `colima start`.
|
|
148
125
|
|
|
149
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
138
|
+
## Contributor notes
|
|
167
139
|
|
|
168
|
-
|
|
140
|
+
To build + test the image from a checkout (instead of pulling ghcr):
|
|
169
141
|
|
|
170
142
|
```bash
|
|
171
|
-
|
|
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
|
-
|
|
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,
|
|
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.
|
|
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",
|