@cerefox/memory 0.4.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT_GUIDE.md +462 -0
- package/AGENT_QUICK_REFERENCE.md +76 -0
- package/README.md +164 -0
- package/dist/bin/{cerefox-mcp.js → cerefox.js} +37752 -23127
- package/docs/guides/access-paths.md +235 -0
- package/docs/guides/agent-coordination.md +163 -0
- package/docs/guides/cli.md +481 -0
- package/docs/guides/configuration.md +460 -0
- package/docs/guides/connect-agents.md +1428 -0
- package/docs/guides/migration-v0.4.md +231 -0
- package/docs/guides/migration-v0.5.md +180 -0
- package/docs/guides/operational-cost.md +113 -0
- package/docs/guides/ops-scripts.md +271 -0
- package/docs/guides/quickstart.md +165 -0
- package/docs/guides/response-limits.md +151 -0
- package/docs/guides/setup-cloud-run.md +117 -0
- package/docs/guides/setup-local.md +178 -0
- package/docs/guides/setup-supabase.md +370 -0
- package/docs/guides/upgrading.md +275 -0
- package/package.json +16 -6
|
@@ -0,0 +1,1428 @@
|
|
|
1
|
+
# Connecting AI Agents to Cerefox
|
|
2
|
+
|
|
3
|
+
Cerefox exposes your knowledge base through two access paths. Choose the one that fits your
|
|
4
|
+
client; you can also run both in parallel.
|
|
5
|
+
|
|
6
|
+
> **OpenAI API key — known glitch (all paths):** The simplest setup is an **unrestricted**
|
|
7
|
+
> OpenAI API key — it just works. If you prefer a restricted key and hit a
|
|
8
|
+
> `Missing scopes: model.request` or 401 error despite the key looking correct in the
|
|
9
|
+
> dashboard, this is a [known OpenAI UI bug](https://community.openai.com/t/missing-scopes-model-request-on-restricted-api-key/1371602):
|
|
10
|
+
> narrowing sub-scopes after setting the top-level **Model Capabilities → Write** permission
|
|
11
|
+
> corrupts the internal permission state silently. The fix is either to switch to an
|
|
12
|
+
> unrestricted key, or to open the key in the
|
|
13
|
+
> [OpenAI dashboard](https://platform.openai.com/api-keys), save it without any changes, and
|
|
14
|
+
> retry — this resets the internal state immediately.
|
|
15
|
+
>
|
|
16
|
+
> This applies to all paths (A-Local, A-Remote, Path B) — any path that calls the OpenAI
|
|
17
|
+
> embedding API can be affected. If you're on Fireworks AI instead, see
|
|
18
|
+
> `docs/guides/configuration.md` → "Changing the embedding model".
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Access paths at a glance
|
|
23
|
+
|
|
24
|
+
Three top-level paths plus a few special cases:
|
|
25
|
+
|
|
26
|
+
- **Path A** — MCP server (local subprocess or remote Edge Function). Best for purpose-built agent clients like Claude Desktop, Cursor, and Claude Code's MCP integration.
|
|
27
|
+
- **Path B** — direct Edge Function HTTP. Best for ChatGPT Custom GPTs and any HTTP caller (curl, scripts).
|
|
28
|
+
- **Path C** — local shell CLI invoked by a coding agent's Bash tool. Best for Claude Code, Codex CLI, opencode, OpenClaw, Hermes, and similar local-agent CLIs **when the user prefers not to configure MCP** but still wants the agent to read and write Cerefox.
|
|
29
|
+
|
|
30
|
+
| Client | Path | Search | Requirements / caveats |
|
|
31
|
+
|--------|------|--------|-----------------------|
|
|
32
|
+
| Claude Desktop (remote) | Path A-Remote — `cerefox-mcp` Edge Function | Hybrid | Node.js for `npx supergateway` or `npx mcp-remote`; no Python needed |
|
|
33
|
+
| Claude Code (remote) | Path A-Remote — `cerefox-mcp` Edge Function | Hybrid | URL + anon key only; no local install |
|
|
34
|
+
| Cursor (remote) | Path A-Remote — `cerefox-mcp` Edge Function | Hybrid | URL + anon key only; no local install |
|
|
35
|
+
| OpenAI Codex CLI (remote) | Path A-Remote — `cerefox-mcp` Edge Function | Hybrid | URL + anon key env var; TOML config |
|
|
36
|
+
| ChatGPT (chatgpt.com or desktop) | Path B — Custom GPT → Edge Functions | Hybrid | ChatGPT Plus required |
|
|
37
|
+
| Claude Desktop (local) | Path A-Local — `@cerefox/memory` via `npx` (recommended) or `cerefox mcp` (Python fallback) | Hybrid | Local alternative; Node.js (npm path) or Python + uv + local clone (legacy path); zero Edge Function invocations |
|
|
38
|
+
| Claude Code (local) | Path A-Local — `@cerefox/memory` via `npx` or `cerefox mcp` | Hybrid | Local alternative; zero Edge Function invocations |
|
|
39
|
+
| Cursor (local) | Path A-Local — `@cerefox/memory` via `npx` or `cerefox mcp` | Hybrid | Local alternative; zero Edge Function invocations |
|
|
40
|
+
| Cloud Claude (claude.ai web) | Remote Supabase MCP | FTS only | No install; search quality limited |
|
|
41
|
+
| Gemini CLI (remote) | Path A-Remote — `cerefox-mcp` Edge Function | Hybrid | URL + anon key only; no local install |
|
|
42
|
+
| Local coding agents (Claude Code, Codex CLI, opencode, OpenClaw, Hermes, …) | Path C — Shell CLI (Bash tool) | Hybrid | Local clone + `uv`; agent runs `uv run cerefox …` as a shell command. Useful when MCP setup is friction. |
|
|
43
|
+
| curl / scripts | Path B — Edge Functions directly | Hybrid | Direct HTTP; no client needed |
|
|
44
|
+
| Custom Python agents | Python SDK directly | Hybrid | Local Python required |
|
|
45
|
+
|
|
46
|
+
> **"Hybrid"** = FTS + semantic, document-level (complete reconstructed notes, not isolated chunks).
|
|
47
|
+
> **"FTS only"** = keyword search only; no semantic/vector search.
|
|
48
|
+
|
|
49
|
+
> **Cloud hybrid for all clients (future)**: deploying the MCP server to Cloud Run would give
|
|
50
|
+
> cloud clients (claude.ai, chatgpt.com) full hybrid search. Tracked in `docs/TODO.md`.
|
|
51
|
+
|
|
52
|
+
> **Perplexity** supports stdio-only MCP on macOS Desktop (via Helper App). Remote MCP is
|
|
53
|
+
> "coming soon." Perplexity's CTO has signalled a strategic shift away from MCP (March 2026),
|
|
54
|
+
> so API-based integration may be the long-term path. Not a priority.
|
|
55
|
+
>
|
|
56
|
+
> **Gemini web** (gemini.google.com) does not support custom MCP servers. No integration path.
|
|
57
|
+
|
|
58
|
+
> **Quick start with templates:** Copy-pasteable `.mcp.json` templates for each client are
|
|
59
|
+
> available in [`examples/mcp-configs/`](../examples/mcp-configs/). Pick the one for your
|
|
60
|
+
> client, replace the placeholders, and you're connected.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Prerequisites
|
|
65
|
+
|
|
66
|
+
**For all paths:**
|
|
67
|
+
- Supabase project set up and schema deployed (see `setup-supabase.md`)
|
|
68
|
+
- Some content ingested (`cerefox ingest my-notes.md`)
|
|
69
|
+
|
|
70
|
+
**For Path A-Local only:**
|
|
71
|
+
- **Recommended (v0.4.0+):** [Node.js ≥20](https://nodejs.org) (for `npx --package=@cerefox/memory cerefox mcp`)
|
|
72
|
+
+ `.env` file in the working directory the client launches the server from (see "env block"
|
|
73
|
+
in the per-client configs below if your client can't see the file)
|
|
74
|
+
- **Alternative:** [`uv`](https://docs.astral.sh/uv/getting-started/installation/) installed on your machine + Cerefox repository cloned locally (e.g. `/Users/yourname/src/cerefox`)
|
|
75
|
+
+ `.env` in the checkout
|
|
76
|
+
- Either way, `.env` must define `CEREFOX_SUPABASE_URL`, `CEREFOX_SUPABASE_KEY`, and your
|
|
77
|
+
embedding API key (`OPENAI_API_KEY`)
|
|
78
|
+
|
|
79
|
+
> **Important — which anon key to use (2026):** Path A-Remote and Path B both require an
|
|
80
|
+
> "anon key" as a Bearer token. As of 2026, you **must** use the **legacy anon JWT**
|
|
81
|
+
> (`eyJ…`) — the new `sb_publishable_…` key is rejected by the Supabase Edge Function
|
|
82
|
+
> gateway with `UNAUTHORIZED_INVALID_JWT_FORMAT`. Find the legacy key in **Project
|
|
83
|
+
> Settings → API Keys → Legacy → anon**. This is a Supabase platform constraint;
|
|
84
|
+
> see [`setup-supabase.md` → Supabase API keys (2026)](setup-supabase.md#supabase-api-keys-2026)
|
|
85
|
+
> for the full story.
|
|
86
|
+
|
|
87
|
+
**For Path A-Remote (remote MCP Edge Function) — recommended:**
|
|
88
|
+
- `cerefox-mcp` Edge Function deployed (`npx supabase functions deploy cerefox-mcp`)
|
|
89
|
+
- Your **legacy anon JWT** (see callout above): Supabase Dashboard → Project Settings → API Keys → Legacy → anon
|
|
90
|
+
- For Claude Desktop: [Node.js](https://nodejs.org) installed (for `npx supergateway` or `npx mcp-remote`)
|
|
91
|
+
- For Claude Code: [Node.js](https://nodejs.org) for `npx mcp-remote` (recommended), or no extra deps for native HTTP
|
|
92
|
+
|
|
93
|
+
**For Path B (Edge Functions / GPT Actions) only:**
|
|
94
|
+
- Supabase Edge Functions deployed: `cerefox-search`, `cerefox-ingest`, `cerefox-metadata`,
|
|
95
|
+
`cerefox-get-document`, `cerefox-list-versions`, `cerefox-get-audit-log`,
|
|
96
|
+
`cerefox-metadata-search`, `cerefox-list-projects` --
|
|
97
|
+
see `setup-supabase.md` for the deploy procedure (`npx supabase functions deploy`)
|
|
98
|
+
- Your **legacy anon JWT** (see callout above): Supabase Dashboard → Project Settings → API Keys → Legacy → anon
|
|
99
|
+
- Your **project ref**: visible in the Supabase Dashboard URL
|
|
100
|
+
(`app.supabase.com/project/<project-ref>`)
|
|
101
|
+
|
|
102
|
+
**For cloud Claude.ai only:**
|
|
103
|
+
- A **Personal Access Token** (PAT): create at `https://supabase.com/dashboard/account/tokens`
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Path A-Local — Local MCP server
|
|
108
|
+
|
|
109
|
+
### What it is
|
|
110
|
+
|
|
111
|
+
The local Cerefox MCP server runs on your machine and exposes the same 10 tools as the remote
|
|
112
|
+
Edge Function, communicating with clients over stdio.
|
|
113
|
+
|
|
114
|
+
As of **v0.4.0** the local server ships as an npm package — **[`@cerefox/memory`](https://www.npmjs.com/package/@cerefox/memory)** — built with the official `@modelcontextprotocol/sdk`.
|
|
115
|
+
The bin entry is `cerefox` (run as `cerefox mcp`). The recommended client config is `npx -y --package=@cerefox/memory cerefox mcp`.
|
|
116
|
+
|
|
117
|
+
The legacy `uv run cerefox mcp` invocation **still works** and is preserved as a soft
|
|
118
|
+
wrapper: it tries `npx --no-install @cerefox/memory cerefox mcp` first and falls back to the
|
|
119
|
+
Python MCP server if npm is unavailable or `@cerefox/memory` isn't installed. New users
|
|
120
|
+
should prefer the npm-native config; existing users don't have to change anything.
|
|
121
|
+
|
|
122
|
+
- Embeddings are computed locally using your `.env` key (no extra credentials)
|
|
123
|
+
- Works offline except for the OpenAI embedding API call per query
|
|
124
|
+
- One setup, all compatible local clients (Claude Desktop, Cursor, Claude Code, Codex CLI, …)
|
|
125
|
+
|
|
126
|
+
See [`docs/guides/migration-v0.4.md`](migration-v0.4.md) for before/after config snippets
|
|
127
|
+
per client.
|
|
128
|
+
|
|
129
|
+
> **Why not `mcp-server-fetch`?** The generic fetch MCP only supports GET requests and cannot
|
|
130
|
+
> make authenticated POST calls to the Edge Functions. The built-in local server is
|
|
131
|
+
> the correct solution.
|
|
132
|
+
|
|
133
|
+
### Path A MCP tools
|
|
134
|
+
|
|
135
|
+
Once configured, every Path A client has these tools:
|
|
136
|
+
|
|
137
|
+
| Tool | Description |
|
|
138
|
+
|------|-------------|
|
|
139
|
+
| `cerefox_search` | Hybrid (FTS + semantic) document-level search. Filter by `project_name` or `metadata_filter`. |
|
|
140
|
+
| `cerefox_ingest` | Save a note or document to the knowledge base. Pass `document_id` to update by ID (deterministic); or `update_if_exists: true` to update by title match. Accepts optional `author` and `project_name`. |
|
|
141
|
+
| `cerefox_list_metadata_keys` | List all metadata keys in use across documents |
|
|
142
|
+
| `cerefox_get_document` | Retrieve the full content of a document (current or archived version) |
|
|
143
|
+
| `cerefox_list_versions` | List all archived versions of a document |
|
|
144
|
+
| `cerefox_get_audit_log` | Query audit log entries with filters (document, author, operation, time range) |
|
|
145
|
+
| `cerefox_list_projects` | List all projects with names and IDs. Use for discovering available projects. |
|
|
146
|
+
| `cerefox_metadata_search` | Find documents by metadata key-value criteria without a text search term. Supports project, date, and content filters. |
|
|
147
|
+
| `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". |
|
|
148
|
+
| `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. |
|
|
149
|
+
|
|
150
|
+
> All 10 tools are available on both Path A (local and remote MCP) and Path B (GPT Actions
|
|
151
|
+
> via dedicated Edge Functions, except `cerefox_get_help` which is MCP-only). MCP tools use
|
|
152
|
+
> `project_name` (human-readable); primitive Edge Functions (Path B) use `project_id` (UUID).
|
|
153
|
+
|
|
154
|
+
### Path A system prompt
|
|
155
|
+
|
|
156
|
+
Set this as Custom Instructions / System Prompt in your client:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
You have access to a personal knowledge base via Cerefox MCP tools.
|
|
160
|
+
When answering questions, always call cerefox_search first with a relevant query.
|
|
161
|
+
Cite doc_title for every claim drawn from the knowledge base.
|
|
162
|
+
Use cerefox_ingest to save anything the user asks you to remember.
|
|
163
|
+
Always set your requestor/author parameter to identify yourself.
|
|
164
|
+
For the full tool reference, search Cerefox for "How AI Agents Use Cerefox".
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
> **Agent reference docs**: `AGENT_GUIDE.md` (comprehensive) and `AGENT_QUICK_REFERENCE.md` (quick
|
|
168
|
+
> reference) in the repo root contain the full tool reference for AI agents. These are also
|
|
169
|
+
> ingested into the Cerefox KB via `sync_docs.py`, so agents can find them by searching.
|
|
170
|
+
|
|
171
|
+
### Path A verification prompts
|
|
172
|
+
|
|
173
|
+
After setup, ask your client:
|
|
174
|
+
|
|
175
|
+
> "What tools do you have available?"
|
|
176
|
+
> Expected: 10 tools listed (`cerefox_search`, `cerefox_ingest`, `cerefox_get_document`,
|
|
177
|
+
> `cerefox_list_versions`, `cerefox_list_projects`, `cerefox_list_metadata_keys`,
|
|
178
|
+
> `cerefox_metadata_search`, `cerefox_set_document_projects`, `cerefox_get_audit_log`,
|
|
179
|
+
> `cerefox_get_help`).
|
|
180
|
+
|
|
181
|
+
> "Use cerefox_search with query='second brain' and match_count=3. What did you find?"
|
|
182
|
+
|
|
183
|
+
> "Save a note titled 'Test Note' with content '# Test\nThis is a test.' using cerefox_ingest."
|
|
184
|
+
|
|
185
|
+
> "Call cerefox_get_help with no topic. What sections are listed?"
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Claude Desktop
|
|
190
|
+
|
|
191
|
+
**Config file location:**
|
|
192
|
+
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
193
|
+
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
194
|
+
|
|
195
|
+
**Recommended — npm (`@cerefox/memory`, v0.4.0+):**
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"mcpServers": {
|
|
200
|
+
"cerefox": {
|
|
201
|
+
"command": "npx",
|
|
202
|
+
"args": ["-y", "--package=@cerefox/memory", "cerefox", "mcp"],
|
|
203
|
+
"env": {
|
|
204
|
+
"CEREFOX_SUPABASE_URL": "https://<your-project-ref>.supabase.co",
|
|
205
|
+
"CEREFOX_SUPABASE_KEY": "<your-service-role-or-sb_secret-key>",
|
|
206
|
+
"OPENAI_API_KEY": "sk-..."
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The `env` block is only needed if you don't already have a `.env` file in a directory the
|
|
214
|
+
server can find — the server resolves `.env` from the current working directory.
|
|
215
|
+
|
|
216
|
+
**Alternative — local checkout (Python or pre-v0.4 setups):**
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"mcpServers": {
|
|
221
|
+
"cerefox": {
|
|
222
|
+
"command": "uv",
|
|
223
|
+
"args": ["--directory", "/path/to/cerefox", "run", "cerefox", "mcp"]
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Replace `/path/to/cerefox` with the absolute path to your Cerefox checkout
|
|
230
|
+
(e.g. `/Users/yourname/src/cerefox` on macOS, `C:\Users\yourname\src\cerefox` on Windows).
|
|
231
|
+
This invocation soft-wraps `npx --package=@cerefox/memory cerefox mcp` when available; otherwise the
|
|
232
|
+
legacy Python MCP server takes over.
|
|
233
|
+
|
|
234
|
+
**Important:**
|
|
235
|
+
- Merge the `mcpServers` block into any existing `claude_desktop_config.json` — do not wrap it
|
|
236
|
+
in an extra `{}` or replace the whole file.
|
|
237
|
+
- Restart Claude Desktop fully (Cmd+Q on macOS, not just close the window) after saving.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### ChatGPT Desktop
|
|
242
|
+
|
|
243
|
+
> **ChatGPT Desktop does not support local stdio MCP servers.**
|
|
244
|
+
> OpenAI's MCP implementation for ChatGPT only supports remote servers via SSE or
|
|
245
|
+
> streaming HTTP — not local subprocess (stdio) servers like `cerefox mcp`.
|
|
246
|
+
> The "dev mode" MCP connector visible in the app also requires a public URL.
|
|
247
|
+
>
|
|
248
|
+
> **Use Path B (Custom GPT + Edge Functions) for all ChatGPT access** — both the web
|
|
249
|
+
> app and the desktop app. The Custom GPT approach is fully validated and works well.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### Cursor
|
|
254
|
+
|
|
255
|
+
1. Open **Cursor Settings** (`Cmd+,`) → **Tools & Integrations** → **MCP** → **Add new global MCP server**
|
|
256
|
+
2. Paste either of the following into the MCP config JSON:
|
|
257
|
+
|
|
258
|
+
**Recommended — npm:**
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"mcpServers": {
|
|
263
|
+
"cerefox": {
|
|
264
|
+
"command": "npx",
|
|
265
|
+
"args": ["-y", "--package=@cerefox/memory", "cerefox", "mcp"],
|
|
266
|
+
"env": {
|
|
267
|
+
"CEREFOX_SUPABASE_URL": "https://<your-project-ref>.supabase.co",
|
|
268
|
+
"CEREFOX_SUPABASE_KEY": "<your-service-role-or-sb_secret-key>",
|
|
269
|
+
"OPENAI_API_KEY": "sk-..."
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Alternative — local checkout:**
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"mcpServers": {
|
|
281
|
+
"cerefox": {
|
|
282
|
+
"command": "uv",
|
|
283
|
+
"args": ["--directory", "/path/to/cerefox", "run", "cerefox", "mcp"]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
3. Save and restart Cursor.
|
|
290
|
+
|
|
291
|
+
Alternatively, add a `.cursor/mcp.json` file in your project root with the same content for
|
|
292
|
+
project-scoped access (committed to git, shared with your team).
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### Claude Code
|
|
297
|
+
|
|
298
|
+
Claude Code (the CLI tool and the **Code** tab inside Claude Desktop) uses its own MCP config —
|
|
299
|
+
separate from `claude_desktop_config.json`. Changes made in one do not affect the other.
|
|
300
|
+
|
|
301
|
+
**Option 1: CLI command — npm (recommended)**
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
claude mcp add --scope user cerefox \
|
|
305
|
+
npx -- -y --package=@cerefox/memory cerefox mcp
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
- `--scope user` makes the server available in every project (stored in `~/.claude/mcp.json`).
|
|
309
|
+
- Use `--scope project` instead to limit it to the current directory (stored in `.mcp.json`).
|
|
310
|
+
|
|
311
|
+
If you don't already have `.env` resolvable from your shell's CWD, add the credentials inline
|
|
312
|
+
by editing the resulting JSON config to add an `env` block (see the Claude Desktop example
|
|
313
|
+
above).
|
|
314
|
+
|
|
315
|
+
Verify:
|
|
316
|
+
```bash
|
|
317
|
+
claude mcp list
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Option 2: CLI command — local checkout (uv)**
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
claude mcp add --scope user cerefox \
|
|
324
|
+
uv -- --directory /path/to/cerefox run cerefox mcp
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
This soft-wraps `npx --package=@cerefox/memory cerefox mcp` when available; otherwise falls back to
|
|
328
|
+
the legacy Python MCP server.
|
|
329
|
+
|
|
330
|
+
**Option 3: `.mcp.json` in project root (project-scoped, committable)**
|
|
331
|
+
|
|
332
|
+
Create `.mcp.json` in the root of the repo you work in:
|
|
333
|
+
|
|
334
|
+
```json
|
|
335
|
+
{
|
|
336
|
+
"mcpServers": {
|
|
337
|
+
"cerefox": {
|
|
338
|
+
"command": "npx",
|
|
339
|
+
"args": ["-y", "--package=@cerefox/memory", "cerefox", "mcp"]
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Code tab inside Claude Desktop:**
|
|
346
|
+
The **Code** tab in Claude Desktop uses the same config as the Claude Code CLI, not
|
|
347
|
+
`claude_desktop_config.json`. Run the `claude mcp add` command above — the Code tab will
|
|
348
|
+
pick it up automatically.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Path A-Remote — Remote MCP Edge Function (`cerefox-mcp`)
|
|
353
|
+
|
|
354
|
+
### What it is
|
|
355
|
+
|
|
356
|
+
`cerefox-mcp` is a Supabase Edge Function that speaks the MCP Streamable HTTP protocol
|
|
357
|
+
(spec 2025-03-26). It calls Postgres RPCs directly via per-tool handlers -- no delegation
|
|
358
|
+
to primitive Edge Functions. This means each MCP tool call costs a single Edge Function
|
|
359
|
+
invocation.
|
|
360
|
+
|
|
361
|
+
A single HTTPS URL gives any remote-capable MCP client all 10 tools with full hybrid
|
|
362
|
+
search -- no Python, no `uv`, no local repository clone needed.
|
|
363
|
+
|
|
364
|
+
**URL format:**
|
|
365
|
+
```
|
|
366
|
+
https://<your-project-ref>.supabase.co/functions/v1/cerefox-mcp
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**When to choose Path A-Remote vs Path A-Local:**
|
|
370
|
+
|
|
371
|
+
| Scenario | Prefer |
|
|
372
|
+
|----------|--------|
|
|
373
|
+
| Default / new setup | Path A-Remote -- no Python, no local clone, one URL works everywhere |
|
|
374
|
+
| Multiple machines / cloud dev environments | Path A-Remote |
|
|
375
|
+
| Minimise Supabase Edge Function usage (free tier limits) | Path A-Local -- zero Edge Function invocations |
|
|
376
|
+
| Offline use or development on the cerefox codebase | Path A-Local -- no network dependency |
|
|
377
|
+
| Lowest latency (same machine, no HTTPS round-trip) | Path A-Local -- slightly faster |
|
|
378
|
+
|
|
379
|
+
**Deploy the Edge Function** (once, after cloning the repo):
|
|
380
|
+
```bash
|
|
381
|
+
npx supabase functions deploy cerefox-mcp
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
### Path A-Remote: Claude Code
|
|
387
|
+
|
|
388
|
+
> **Recommended: use `mcp-remote` stdio bridge.** While the SSE idle polling issue has been
|
|
389
|
+
> fixed server-side (v0.1.12 -- the server returns 405 for GET per the MCP spec), `mcp-remote`
|
|
390
|
+
> is still recommended because it cleanly bypasses Supabase's GoTrace OAuth discovery conflict
|
|
391
|
+
> via `--header`. See [issue #17](https://github.com/fstamatelopoulos/cerefox/issues/17) for
|
|
392
|
+
> the full investigation.
|
|
393
|
+
|
|
394
|
+
**Option 1 — `mcp-remote` (recommended):**
|
|
395
|
+
|
|
396
|
+
Add to your project's `.mcp.json` (or copy
|
|
397
|
+
[`examples/mcp-configs/claude-code-remote.json`](../examples/mcp-configs/claude-code-remote.json)):
|
|
398
|
+
|
|
399
|
+
```json
|
|
400
|
+
{
|
|
401
|
+
"mcpServers": {
|
|
402
|
+
"cerefox": {
|
|
403
|
+
"command": "npx",
|
|
404
|
+
"args": [
|
|
405
|
+
"mcp-remote",
|
|
406
|
+
"https://<your-project-ref>.supabase.co/functions/v1/cerefox-mcp",
|
|
407
|
+
"--header",
|
|
408
|
+
"Authorization: Bearer <your-anon-key>"
|
|
409
|
+
]
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Option 2 — native HTTP:**
|
|
416
|
+
|
|
417
|
+
Claude Code also supports Streamable HTTP natively. This works and no longer has idle polling
|
|
418
|
+
overhead (fixed in v0.1.12). However, `mcp-remote` is still preferred for the OAuth bypass.
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
claude mcp add --transport http cerefox \
|
|
422
|
+
https://<your-project-ref>.supabase.co/functions/v1/cerefox-mcp \
|
|
423
|
+
--header "Authorization: Bearer <your-anon-key>"
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Verify:
|
|
427
|
+
```bash
|
|
428
|
+
claude mcp list
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
For a user-scoped server (available in all projects), add `--scope user`:
|
|
432
|
+
```bash
|
|
433
|
+
claude mcp add --transport http --scope user cerefox \
|
|
434
|
+
https://<your-project-ref>.supabase.co/functions/v1/cerefox-mcp \
|
|
435
|
+
--header "Authorization: Bearer <your-anon-key>"
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
### Path A-Remote: Cursor
|
|
441
|
+
|
|
442
|
+
Cursor supports remote MCP servers natively via `url` + `headers` in `mcp.json`.
|
|
443
|
+
|
|
444
|
+
1. Open **Cursor Settings** (`Cmd+,`) → **Tools & Integrations** → **MCP** → **Add new global MCP server**
|
|
445
|
+
2. Paste this config (replace the placeholders):
|
|
446
|
+
|
|
447
|
+
```json
|
|
448
|
+
{
|
|
449
|
+
"mcpServers": {
|
|
450
|
+
"cerefox": {
|
|
451
|
+
"url": "https://<your-project-ref>.supabase.co/functions/v1/cerefox-mcp",
|
|
452
|
+
"headers": {
|
|
453
|
+
"Authorization": "Bearer <your-anon-key>"
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
3. Save and restart Cursor.
|
|
461
|
+
|
|
462
|
+
Alternatively, add `.cursor/mcp.json` in your project root with the same content for
|
|
463
|
+
project-scoped access.
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
### Path A-Remote: Claude Desktop
|
|
468
|
+
|
|
469
|
+
Claude Desktop does not support remote MCP servers natively -- it requires a local subprocess
|
|
470
|
+
(`command` field). Use [`supergateway`](https://www.npmjs.com/package/supergateway) or
|
|
471
|
+
[`mcp-remote`](https://www.npmjs.com/package/mcp-remote) as a stdio-to-HTTP bridge.
|
|
472
|
+
|
|
473
|
+
> **`supergateway` vs `mcp-remote` for Claude Desktop:** `mcp-remote --header` works for
|
|
474
|
+
> Claude Code (tested). For Claude Desktop, `supergateway` is the tested and confirmed option.
|
|
475
|
+
> `mcp-remote` may also work for Claude Desktop now that the 405 SSE fix is in place, but
|
|
476
|
+
> this has not been verified. If you try it, use the same config as Claude Code.
|
|
477
|
+
|
|
478
|
+
**Requirements:** [Node.js](https://nodejs.org) installed (for `npx`).
|
|
479
|
+
|
|
480
|
+
**Config file location:**
|
|
481
|
+
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
482
|
+
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
483
|
+
|
|
484
|
+
Add (or merge into) the file:
|
|
485
|
+
|
|
486
|
+
```json
|
|
487
|
+
{
|
|
488
|
+
"mcpServers": {
|
|
489
|
+
"cerefox": {
|
|
490
|
+
"command": "npx",
|
|
491
|
+
"args": [
|
|
492
|
+
"-y", "supergateway",
|
|
493
|
+
"--streamableHttp", "https://<your-project-ref>.supabase.co/functions/v1/cerefox-mcp",
|
|
494
|
+
"--oauth2Bearer", "<your-anon-key>"
|
|
495
|
+
]
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
Replace `<your-project-ref>` and `<your-anon-key>` with your actual values.
|
|
502
|
+
|
|
503
|
+
**Important:**
|
|
504
|
+
- Restart Claude Desktop fully (Cmd+Q on macOS) after saving the config.
|
|
505
|
+
- `-y` tells npx to auto-install `supergateway` without prompting.
|
|
506
|
+
- No Python, no local repo clone, no `.env` file needed — just the URL and anon key.
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
### Path A-Remote: OpenAI Codex CLI
|
|
511
|
+
|
|
512
|
+
[Codex](https://github.com/openai/codex) supports remote MCP servers natively via Streamable
|
|
513
|
+
HTTP. Configuration uses TOML (not JSON like most other MCP clients).
|
|
514
|
+
|
|
515
|
+
**Step 1 — Set the anon key as an environment variable:**
|
|
516
|
+
|
|
517
|
+
Codex references Bearer tokens by environment variable name, not by value. Add to your
|
|
518
|
+
`~/.zshrc` (or `~/.bashrc`):
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
export CEREFOX_ANON_KEY="<your-anon-key>"
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
Then reload: `source ~/.zshrc`
|
|
525
|
+
|
|
526
|
+
**Step 2 — Add the server to `~/.codex/config.toml`:**
|
|
527
|
+
|
|
528
|
+
```toml
|
|
529
|
+
[mcp_servers.cerefox]
|
|
530
|
+
url = "https://<your-project-ref>.supabase.co/functions/v1/cerefox-mcp"
|
|
531
|
+
bearer_token_env_var = "CEREFOX_ANON_KEY"
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
Replace `<your-project-ref>` with your Supabase project ref.
|
|
535
|
+
|
|
536
|
+
**Step 3 — Verify:**
|
|
537
|
+
|
|
538
|
+
Launch Codex and use the `/mcp` slash command to confirm the `cerefox` server is connected
|
|
539
|
+
and all 10 tools are listed.
|
|
540
|
+
|
|
541
|
+
**Notes:**
|
|
542
|
+
- `bearer_token_env_var` is the **name** of the env var (e.g. `"CEREFOX_ANON_KEY"`), not the
|
|
543
|
+
token itself. Codex reads the value at runtime.
|
|
544
|
+
- No Python, no local repo clone needed — just the URL and anon key.
|
|
545
|
+
- No idle SSE polling cost — the 405 GET fix in `cerefox-mcp` prevents it.
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
### Path A-Remote: Gemini CLI
|
|
550
|
+
|
|
551
|
+
[Gemini CLI](https://github.com/google-gemini/gemini-cli) supports Streamable HTTP with static
|
|
552
|
+
Bearer token headers natively — no bridge needed. Architecturally identical to Claude Code and
|
|
553
|
+
Cursor.
|
|
554
|
+
|
|
555
|
+
**Config file location:**
|
|
556
|
+
- Global: `~/.gemini/settings.json`
|
|
557
|
+
- Project: `.gemini/settings.json` in the project root
|
|
558
|
+
|
|
559
|
+
Add (or merge into) the file:
|
|
560
|
+
|
|
561
|
+
```json
|
|
562
|
+
{
|
|
563
|
+
"mcpServers": {
|
|
564
|
+
"cerefox": {
|
|
565
|
+
"httpUrl": "https://<your-project-ref>.supabase.co/functions/v1/cerefox-mcp",
|
|
566
|
+
"headers": {
|
|
567
|
+
"Authorization": "Bearer <your-anon-key>"
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Replace `<your-project-ref>` and `<your-anon-key>` with your actual values.
|
|
575
|
+
|
|
576
|
+
**Verify:**
|
|
577
|
+
|
|
578
|
+
Launch `gemini` and use `/mcp` to confirm tools are listed, or ask:
|
|
579
|
+
> "What tools do you have available?"
|
|
580
|
+
|
|
581
|
+
**Notes:**
|
|
582
|
+
- Use `httpUrl` (not `url`) for Streamable HTTP transport.
|
|
583
|
+
- Static headers bypass OAuth discovery entirely — no GoTrue conflict.
|
|
584
|
+
- No Python, no local repo clone needed.
|
|
585
|
+
- Status: **untested** — expected to work based on architecture match with Claude Code/Cursor.
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
## Path B — Supabase Edge Functions (HTTP)
|
|
590
|
+
|
|
591
|
+
### What they are
|
|
592
|
+
|
|
593
|
+
TypeScript functions deployed to Supabase, callable over HTTPS from anywhere — no local install,
|
|
594
|
+
no MCP client needed. Embeddings are computed server-side using the `OPENAI_API_KEY` secret
|
|
595
|
+
stored in Supabase.
|
|
596
|
+
|
|
597
|
+
- Works from cloud agents (ChatGPT GPT Actions, scripts, CI pipelines)
|
|
598
|
+
- No user machine required; Supabase handles all infrastructure
|
|
599
|
+
- Constraint: embedding model is hardcoded in TypeScript — requires redeployment when changed
|
|
600
|
+
(see `docs/guides/configuration.md` → "Changing the embedding model")
|
|
601
|
+
|
|
602
|
+
### Path B authentication
|
|
603
|
+
|
|
604
|
+
All Edge Function calls require:
|
|
605
|
+
|
|
606
|
+
```
|
|
607
|
+
Authorization: Bearer <your-anon-key>
|
|
608
|
+
Content-Type: application/json
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
Find your anon key: **Supabase Dashboard → Project Settings → API Keys → Legacy → anon** (use the legacy JWT, not the new `sb_publishable_…` — see the API keys callout in the Prerequisites section).
|
|
612
|
+
|
|
613
|
+
### Path B system prompt
|
|
614
|
+
|
|
615
|
+
For ChatGPT Custom GPT:
|
|
616
|
+
```
|
|
617
|
+
You have access to a personal knowledge base via the searchKnowledgeBase action.
|
|
618
|
+
When the user asks a question, always search the knowledge base first using a
|
|
619
|
+
relevant query. Present results by document title, citing the source for every claim.
|
|
620
|
+
Use ingestNote to save any new information the user asks you to remember.
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### Path B verification
|
|
624
|
+
|
|
625
|
+
```bash
|
|
626
|
+
curl -s -X POST \
|
|
627
|
+
"https://<your-project-ref>.supabase.co/functions/v1/cerefox-search" \
|
|
628
|
+
-H "Authorization: Bearer <your-anon-key>" \
|
|
629
|
+
-H "Content-Type: application/json" \
|
|
630
|
+
-d '{"query": "second brain", "match_count": 3}'
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
Expected: JSON response with `results` array containing documents.
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
### ChatGPT Custom GPT (cloud — chatgpt.com)
|
|
638
|
+
|
|
639
|
+
A Custom GPT with Actions pointing at the Edge Functions gives ChatGPT full hybrid search from
|
|
640
|
+
any browser — no local install, no MCP client, works free with ChatGPT Plus.
|
|
641
|
+
|
|
642
|
+
**Step 1 — Create the Custom GPT**
|
|
643
|
+
|
|
644
|
+
1. Go to **chatgpt.com → Explore GPTs → Create**
|
|
645
|
+
2. Name it (e.g. "Cerefox Assistant")
|
|
646
|
+
3. Paste the system prompt from "Path B system prompt" above into the **Instructions** field
|
|
647
|
+
4. Click **Create new action**
|
|
648
|
+
|
|
649
|
+
**Step 2 — Paste the OpenAPI schema**
|
|
650
|
+
|
|
651
|
+
In the action editor, paste this schema (replace `<your-project-ref>`):
|
|
652
|
+
|
|
653
|
+
```yaml
|
|
654
|
+
openapi: 3.1.0
|
|
655
|
+
info:
|
|
656
|
+
title: Cerefox Knowledge Base
|
|
657
|
+
version: 1.7.0
|
|
658
|
+
servers:
|
|
659
|
+
- url: https://<your-project-ref>.supabase.co/functions/v1
|
|
660
|
+
paths:
|
|
661
|
+
/cerefox-search:
|
|
662
|
+
post:
|
|
663
|
+
operationId: searchKnowledgeBase
|
|
664
|
+
summary: Search the knowledge base (hybrid FTS + semantic, document-level)
|
|
665
|
+
requestBody:
|
|
666
|
+
required: true
|
|
667
|
+
content:
|
|
668
|
+
application/json:
|
|
669
|
+
schema:
|
|
670
|
+
type: object
|
|
671
|
+
required: [query]
|
|
672
|
+
properties:
|
|
673
|
+
query:
|
|
674
|
+
type: string
|
|
675
|
+
match_count:
|
|
676
|
+
type: integer
|
|
677
|
+
default: 5
|
|
678
|
+
project_name:
|
|
679
|
+
type: string
|
|
680
|
+
mode:
|
|
681
|
+
type: string
|
|
682
|
+
default: docs
|
|
683
|
+
metadata_filter:
|
|
684
|
+
type: object
|
|
685
|
+
additionalProperties:
|
|
686
|
+
type: string
|
|
687
|
+
description: >
|
|
688
|
+
Optional JSONB containment filter. Only documents whose metadata
|
|
689
|
+
contains ALL specified key-value pairs are returned.
|
|
690
|
+
Example: {"type": "decision", "status": "active"}.
|
|
691
|
+
Call listMetadataKeys to discover available keys and their values.
|
|
692
|
+
Omit or set to null to search all documents.
|
|
693
|
+
requestor:
|
|
694
|
+
type: string
|
|
695
|
+
description: >
|
|
696
|
+
Name of the agent making this request (e.g., "ChatGPT").
|
|
697
|
+
Recorded in the usage log for attribution. Optional.
|
|
698
|
+
responses:
|
|
699
|
+
'200':
|
|
700
|
+
description: >
|
|
701
|
+
{ results, query, mode, match_count, project_name, metadata_filter, truncated, response_bytes }.
|
|
702
|
+
Each item in results (docs mode) contains: document_id, doc_title, full_content,
|
|
703
|
+
chunk_count, total_chars, best_score, is_partial.
|
|
704
|
+
is_partial is true when the document exceeded the small-to-big threshold — in that
|
|
705
|
+
case full_content contains matched chunks plus their neighbours rather than the
|
|
706
|
+
complete document, and total_chars still reflects the full document size.
|
|
707
|
+
/cerefox-ingest:
|
|
708
|
+
post:
|
|
709
|
+
operationId: ingestNote
|
|
710
|
+
summary: >
|
|
711
|
+
Save a note to the knowledge base. When update_if_exists is true and the
|
|
712
|
+
document already exists, the previous version is archived automatically —
|
|
713
|
+
you can retrieve it later with getDocument.
|
|
714
|
+
requestBody:
|
|
715
|
+
required: true
|
|
716
|
+
content:
|
|
717
|
+
application/json:
|
|
718
|
+
schema:
|
|
719
|
+
type: object
|
|
720
|
+
required: [title, content]
|
|
721
|
+
properties:
|
|
722
|
+
title:
|
|
723
|
+
type: string
|
|
724
|
+
content:
|
|
725
|
+
type: string
|
|
726
|
+
document_id:
|
|
727
|
+
type: string
|
|
728
|
+
description: >
|
|
729
|
+
UUID of an existing document to update. When provided, updates
|
|
730
|
+
that document directly regardless of update_if_exists. Returns
|
|
731
|
+
an error if the document does not exist. Workflow: search for
|
|
732
|
+
the document, note the document_id, pass it here.
|
|
733
|
+
project_name:
|
|
734
|
+
type: string
|
|
735
|
+
source:
|
|
736
|
+
type: string
|
|
737
|
+
default: agent
|
|
738
|
+
metadata:
|
|
739
|
+
type: object
|
|
740
|
+
update_if_exists:
|
|
741
|
+
type: boolean
|
|
742
|
+
default: false
|
|
743
|
+
description: >
|
|
744
|
+
When true, update an existing document with the same title
|
|
745
|
+
instead of creating a new one. The previous content is archived
|
|
746
|
+
as a version. If content is unchanged, the document is skipped
|
|
747
|
+
(no re-indexing). Ignored when document_id is provided.
|
|
748
|
+
author:
|
|
749
|
+
type: string
|
|
750
|
+
description: >
|
|
751
|
+
Name of the agent or tool performing the ingestion (e.g.,
|
|
752
|
+
"ChatGPT", "Claude Code"). Recorded in the audit log for
|
|
753
|
+
attribution. Defaults to "agent" if not provided.
|
|
754
|
+
author_type:
|
|
755
|
+
type: string
|
|
756
|
+
enum: [user, agent]
|
|
757
|
+
default: agent
|
|
758
|
+
description: >
|
|
759
|
+
Whether this write is from a human user or an AI agent.
|
|
760
|
+
Controls review_status auto-transition: agent writes set
|
|
761
|
+
the document to pending_review, user writes set it to approved.
|
|
762
|
+
responses:
|
|
763
|
+
'200':
|
|
764
|
+
description: Ingest result
|
|
765
|
+
/cerefox-metadata:
|
|
766
|
+
post:
|
|
767
|
+
operationId: listMetadataKeys
|
|
768
|
+
summary: List all metadata keys in use across documents with counts and example values
|
|
769
|
+
requestBody:
|
|
770
|
+
required: true
|
|
771
|
+
content:
|
|
772
|
+
application/json:
|
|
773
|
+
schema:
|
|
774
|
+
type: object
|
|
775
|
+
properties:
|
|
776
|
+
requestor:
|
|
777
|
+
type: string
|
|
778
|
+
description: Name of the agent making this request. Optional.
|
|
779
|
+
responses:
|
|
780
|
+
'200':
|
|
781
|
+
description: Array of metadata keys with doc_count and example_values
|
|
782
|
+
/cerefox-get-document:
|
|
783
|
+
post:
|
|
784
|
+
operationId: getDocument
|
|
785
|
+
summary: >
|
|
786
|
+
Retrieve the full reconstructed content of a document (current version or a specific
|
|
787
|
+
archived version). Use listVersions first to discover available version UUIDs.
|
|
788
|
+
requestBody:
|
|
789
|
+
required: true
|
|
790
|
+
content:
|
|
791
|
+
application/json:
|
|
792
|
+
schema:
|
|
793
|
+
type: object
|
|
794
|
+
required: [document_id]
|
|
795
|
+
properties:
|
|
796
|
+
document_id:
|
|
797
|
+
type: string
|
|
798
|
+
description: UUID of the document to retrieve
|
|
799
|
+
version_id:
|
|
800
|
+
type: string
|
|
801
|
+
description: >
|
|
802
|
+
UUID of a specific archived version to retrieve. Omit (or pass null)
|
|
803
|
+
for the current version. Version UUIDs are returned by listVersions.
|
|
804
|
+
requestor:
|
|
805
|
+
type: string
|
|
806
|
+
description: Name of the agent making this request. Optional.
|
|
807
|
+
responses:
|
|
808
|
+
'200':
|
|
809
|
+
description: >
|
|
810
|
+
Document content and metadata:
|
|
811
|
+
{ document_id, doc_title, full_content, chunk_count, total_chars,
|
|
812
|
+
is_archived, version_id }
|
|
813
|
+
'404':
|
|
814
|
+
description: Document not found
|
|
815
|
+
/cerefox-list-versions:
|
|
816
|
+
post:
|
|
817
|
+
operationId: listVersions
|
|
818
|
+
summary: >
|
|
819
|
+
List all archived versions of a document, newest first. Returns version UUIDs
|
|
820
|
+
to pass to getDocument for historical content retrieval.
|
|
821
|
+
requestBody:
|
|
822
|
+
required: true
|
|
823
|
+
content:
|
|
824
|
+
application/json:
|
|
825
|
+
schema:
|
|
826
|
+
type: object
|
|
827
|
+
required: [document_id]
|
|
828
|
+
properties:
|
|
829
|
+
document_id:
|
|
830
|
+
type: string
|
|
831
|
+
description: UUID of the document whose version history to list
|
|
832
|
+
requestor:
|
|
833
|
+
type: string
|
|
834
|
+
description: Name of the agent making this request. Optional.
|
|
835
|
+
responses:
|
|
836
|
+
'200':
|
|
837
|
+
description: >
|
|
838
|
+
Array of version objects (empty array if no versions exist):
|
|
839
|
+
[{ version_id, version_number, source, chunk_count, total_chars, archived, created_at }]
|
|
840
|
+
/cerefox-get-audit-log:
|
|
841
|
+
post:
|
|
842
|
+
operationId: getAuditLog
|
|
843
|
+
summary: >
|
|
844
|
+
Query audit log entries with optional filters. Returns entries with document
|
|
845
|
+
titles, author attribution, operation types, size changes, and descriptions.
|
|
846
|
+
requestBody:
|
|
847
|
+
required: true
|
|
848
|
+
content:
|
|
849
|
+
application/json:
|
|
850
|
+
schema:
|
|
851
|
+
type: object
|
|
852
|
+
properties:
|
|
853
|
+
document_id:
|
|
854
|
+
type: string
|
|
855
|
+
description: Filter by document UUID (optional)
|
|
856
|
+
author:
|
|
857
|
+
type: string
|
|
858
|
+
description: Filter by author name (optional)
|
|
859
|
+
operation:
|
|
860
|
+
type: string
|
|
861
|
+
description: >
|
|
862
|
+
Filter by operation type: create, update-content, update-metadata,
|
|
863
|
+
delete, status-change, archive, unarchive (optional)
|
|
864
|
+
since:
|
|
865
|
+
type: string
|
|
866
|
+
description: ISO timestamp lower bound for temporal queries (optional)
|
|
867
|
+
limit:
|
|
868
|
+
type: integer
|
|
869
|
+
default: 50
|
|
870
|
+
description: Max entries to return (max 200)
|
|
871
|
+
requestor:
|
|
872
|
+
type: string
|
|
873
|
+
description: Name of the agent making this request. Optional.
|
|
874
|
+
responses:
|
|
875
|
+
'200':
|
|
876
|
+
description: >
|
|
877
|
+
Array of audit log entries:
|
|
878
|
+
[{ id, document_id, doc_title, version_id, operation, author, author_type,
|
|
879
|
+
size_before, size_after, description, created_at }]
|
|
880
|
+
/cerefox-list-projects:
|
|
881
|
+
post:
|
|
882
|
+
operationId: listProjects
|
|
883
|
+
summary: List all projects with their names, IDs, and descriptions
|
|
884
|
+
requestBody:
|
|
885
|
+
required: true
|
|
886
|
+
content:
|
|
887
|
+
application/json:
|
|
888
|
+
schema:
|
|
889
|
+
type: object
|
|
890
|
+
properties:
|
|
891
|
+
requestor:
|
|
892
|
+
type: string
|
|
893
|
+
description: Name of the agent making this request. Optional.
|
|
894
|
+
responses:
|
|
895
|
+
'200':
|
|
896
|
+
description: >
|
|
897
|
+
Array of projects: [{ id, name, description }]
|
|
898
|
+
/cerefox-metadata-search:
|
|
899
|
+
post:
|
|
900
|
+
operationId: metadataSearch
|
|
901
|
+
summary: >
|
|
902
|
+
Find documents by metadata key-value criteria without a text search term.
|
|
903
|
+
Use to discover documents tagged with specific attributes or browse by taxonomy.
|
|
904
|
+
requestBody:
|
|
905
|
+
required: true
|
|
906
|
+
content:
|
|
907
|
+
application/json:
|
|
908
|
+
schema:
|
|
909
|
+
type: object
|
|
910
|
+
required: [metadata_filter]
|
|
911
|
+
properties:
|
|
912
|
+
metadata_filter:
|
|
913
|
+
type: object
|
|
914
|
+
additionalProperties:
|
|
915
|
+
type: string
|
|
916
|
+
description: >
|
|
917
|
+
Key-value pairs; ALL must match (AND semantics).
|
|
918
|
+
Example: {"type": "decision", "status": "active"}.
|
|
919
|
+
project_id:
|
|
920
|
+
type: string
|
|
921
|
+
description: Filter by project UUID (optional)
|
|
922
|
+
updated_since:
|
|
923
|
+
type: string
|
|
924
|
+
description: ISO-8601 timestamp; only docs updated on/after (optional)
|
|
925
|
+
created_since:
|
|
926
|
+
type: string
|
|
927
|
+
description: ISO-8601 timestamp; only docs created on/after (optional)
|
|
928
|
+
limit:
|
|
929
|
+
type: integer
|
|
930
|
+
default: 10
|
|
931
|
+
include_content:
|
|
932
|
+
type: boolean
|
|
933
|
+
default: false
|
|
934
|
+
description: Include full document text in results
|
|
935
|
+
requestor:
|
|
936
|
+
type: string
|
|
937
|
+
description: Name of the agent making this request. Optional.
|
|
938
|
+
responses:
|
|
939
|
+
'200':
|
|
940
|
+
description: >
|
|
941
|
+
Array of matching documents:
|
|
942
|
+
[{ document_id, title, doc_metadata, review_status, source, created_at,
|
|
943
|
+
updated_at, total_chars, chunk_count, project_ids, project_names,
|
|
944
|
+
version_count, content }]
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
**Step 3 — Configure authentication**
|
|
948
|
+
|
|
949
|
+
In the action's **Authentication** settings:
|
|
950
|
+
- Type: **API Key**
|
|
951
|
+
- Auth type: **Bearer**
|
|
952
|
+
- API key: your Supabase **anon key**
|
|
953
|
+
|
|
954
|
+
> **Important:** ChatGPT may reset the API key when you update the action schema.
|
|
955
|
+
> If you get a 403 error after changing the schema, re-enter the anon key in the
|
|
956
|
+
> authentication settings — the functions themselves are fine.
|
|
957
|
+
|
|
958
|
+
**Step 4 — Save and test**
|
|
959
|
+
|
|
960
|
+
Save the GPT. In a new chat, ask:
|
|
961
|
+
> "Search my knowledge base for 'second brain'."
|
|
962
|
+
|
|
963
|
+
> **Cost**: GPT Actions are free with ChatGPT Plus. Each search call uses a small amount of
|
|
964
|
+
> OpenAI API credits for embedding the query. See `docs/guides/operational-cost.md`.
|
|
965
|
+
|
|
966
|
+
---
|
|
967
|
+
|
|
968
|
+
### curl / scripts
|
|
969
|
+
|
|
970
|
+
Direct HTTP access — useful for shell scripts, CI pipelines, or one-off queries.
|
|
971
|
+
|
|
972
|
+
**Search:**
|
|
973
|
+
```bash
|
|
974
|
+
curl -s -X POST \
|
|
975
|
+
"https://<your-project-ref>.supabase.co/functions/v1/cerefox-search" \
|
|
976
|
+
-H "Authorization: Bearer <your-anon-key>" \
|
|
977
|
+
-H "Content-Type: application/json" \
|
|
978
|
+
-d '{"query": "knowledge management", "match_count": 5}'
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
**Ingest:**
|
|
982
|
+
```bash
|
|
983
|
+
curl -s -X POST \
|
|
984
|
+
"https://<your-project-ref>.supabase.co/functions/v1/cerefox-ingest" \
|
|
985
|
+
-H "Authorization: Bearer <your-anon-key>" \
|
|
986
|
+
-H "Content-Type: application/json" \
|
|
987
|
+
-d '{
|
|
988
|
+
"title": "Meeting Notes 2026-03-11",
|
|
989
|
+
"content": "# Meeting Notes\n\n## Q1 Roadmap\n\nWe agreed to prioritize...",
|
|
990
|
+
"project_name": "Work",
|
|
991
|
+
"source": "agent"
|
|
992
|
+
}'
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
If the same content was already ingested (SHA-256 hash match), returns `"skipped": true`.
|
|
996
|
+
|
|
997
|
+
**Edge Function parameters — `cerefox-search`:**
|
|
998
|
+
|
|
999
|
+
| Parameter | Type | Default | Description |
|
|
1000
|
+
|-----------|------|---------|-------------|
|
|
1001
|
+
| `query` | string | required | Natural-language search query |
|
|
1002
|
+
| `project_name` | string | optional | Filter by project name (case-insensitive) |
|
|
1003
|
+
| `match_count` | number | 5 | Maximum **documents** to return |
|
|
1004
|
+
| `mode` | string | `"docs"` | `"docs"` = full document results (recommended) |
|
|
1005
|
+
| `alpha` | number | 0.7 | Semantic weight (0 = FTS only, 1 = semantic only) |
|
|
1006
|
+
| `min_score` | number | 0.5 | Minimum cosine similarity threshold |
|
|
1007
|
+
| `max_bytes` | number | 200000 | Response size budget in bytes. Results are dropped whole (never truncated mid-document) once the budget is reached. The response includes `truncated: true` and `response_bytes` when the limit was hit. See "Response size limit" below. |
|
|
1008
|
+
|
|
1009
|
+
**Response envelope fields:**
|
|
1010
|
+
|
|
1011
|
+
| Field | Type | Description |
|
|
1012
|
+
|-------|------|-------------|
|
|
1013
|
+
| `results` | array | Matched documents or chunks (see per-row fields below) |
|
|
1014
|
+
| `query` | string | The original query |
|
|
1015
|
+
| `mode` | string | Search mode used |
|
|
1016
|
+
| `match_count` | number | `match_count` value used |
|
|
1017
|
+
| `project_name` | string\|null | Project filter applied (if any) |
|
|
1018
|
+
| `truncated` | boolean | `true` when results were dropped to stay within `max_bytes` |
|
|
1019
|
+
| `response_bytes` | number | Actual bytes in the returned `results` array |
|
|
1020
|
+
|
|
1021
|
+
**Per-result row fields (`docs` mode — the recommended default):**
|
|
1022
|
+
|
|
1023
|
+
| Field | Type | Description |
|
|
1024
|
+
|-------|------|-------------|
|
|
1025
|
+
| `document_id` | string | UUID of the matched document |
|
|
1026
|
+
| `doc_title` | string | Document title |
|
|
1027
|
+
| `doc_source` | string | Origin: `"file"`, `"paste"`, `"agent"` |
|
|
1028
|
+
| `doc_metadata` | object | Arbitrary JSON metadata |
|
|
1029
|
+
| `best_score` | number | Highest chunk relevance score (0–1) |
|
|
1030
|
+
| `best_chunk_heading_path` | string[] | Heading breadcrumb of the best-scoring chunk |
|
|
1031
|
+
| `full_content` | string | Reconstructed document content (may be partial — see `is_partial`) |
|
|
1032
|
+
| `chunk_count` | integer | Number of chunks in `full_content` |
|
|
1033
|
+
| `total_chars` | integer | Full document size in characters (always the whole doc, even when `is_partial` is true) |
|
|
1034
|
+
| `is_partial` | boolean | `true` when `full_content` contains only matched chunks + neighbours instead of the complete document. Triggered when the document exceeds the small-to-big threshold (default 40 000 chars). Use `getDocument` to retrieve the full text. |
|
|
1035
|
+
| `doc_updated_at` | string | ISO 8601 timestamp of the last document update |
|
|
1036
|
+
| `version_count` | integer | Number of archived versions (0 if never updated) |
|
|
1037
|
+
| `doc_project_ids` | string[] | Project UUIDs the document belongs to |
|
|
1038
|
+
|
|
1039
|
+
**Response size limit (`max_bytes`):**
|
|
1040
|
+
|
|
1041
|
+
200 KB is a safety ceiling that prevents runaway responses under unusual settings (e.g. very high `match_count`). Under normal usage the small-to-big retrieval path already keeps individual large-document results compact (matched chunks + neighbours only), so this limit is rarely reached.
|
|
1042
|
+
|
|
1043
|
+
You can override it per-request if needed:
|
|
1044
|
+
```json
|
|
1045
|
+
{ "query": "deployment checklist", "max_bytes": 400000 }
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
See `docs/guides/configuration.md` → "Response size limit" for full details.
|
|
1049
|
+
|
|
1050
|
+
---
|
|
1051
|
+
|
|
1052
|
+
### Cloud Claude (claude.ai web)
|
|
1053
|
+
|
|
1054
|
+
Claude.ai web can connect to the Supabase-hosted remote MCP (no local install):
|
|
1055
|
+
|
|
1056
|
+
1. In Claude.ai: **Settings → Integrations → Add integration**
|
|
1057
|
+
2. Enter the MCP URL:
|
|
1058
|
+
```
|
|
1059
|
+
https://mcp.supabase.com/sse?project_ref=<your-project-ref>
|
|
1060
|
+
```
|
|
1061
|
+
3. Authenticate with your Personal Access Token when prompted.
|
|
1062
|
+
|
|
1063
|
+
> **Limitation**: The cloud Supabase MCP only supports **FTS keyword search** — no hybrid or
|
|
1064
|
+
> semantic search. For full hybrid search from the web, deploy the MCP server to Cloud Run
|
|
1065
|
+
> (see `docs/TODO.md` → "Remote HTTP MCP server").
|
|
1066
|
+
|
|
1067
|
+
---
|
|
1068
|
+
|
|
1069
|
+
## Path C — Shell CLI for local coding agents
|
|
1070
|
+
|
|
1071
|
+
### What it is
|
|
1072
|
+
|
|
1073
|
+
Modern local coding agents — Claude Code, OpenAI Codex CLI, opencode, OpenClaw, Hermes, and many others — all expose a **Bash tool** (or similar shell-execution tool) to their underlying model. If the agent's user grants the agent access to a checked-out Cerefox repo, the agent can read and write the knowledge base by running `uv run cerefox …` exactly the same way a human would.
|
|
1074
|
+
|
|
1075
|
+
This is **not a separate Cerefox installation path** — it's the same Layer 2 access (Python REST + service-role key) that you already use as a human via the CLI. What's new is the *usage model*: the user authorizes a local agent to use that CLI on their behalf, instead of (or alongside) configuring MCP.
|
|
1076
|
+
|
|
1077
|
+
When to choose Path C over Path A:
|
|
1078
|
+
|
|
1079
|
+
- **No MCP setup friction** — the agent already has a Bash tool; no `.mcp.json`, no `claude mcp add`, no Claude Desktop config edits.
|
|
1080
|
+
- **One Cerefox checkout serves any number of local agents** — Claude Code, Codex CLI, opencode, etc. running in the same project all use the same `uv run cerefox …` commands.
|
|
1081
|
+
- **Best for power users who already use the CLI themselves** — the agent and the user share one mental model and one set of conventions.
|
|
1082
|
+
|
|
1083
|
+
When Path A is still better:
|
|
1084
|
+
|
|
1085
|
+
- Cleaner agent UX — named tool calls (`cerefox_search(...)`) read better in agent transcripts than `Bash("uv run cerefox search 'foo'")`.
|
|
1086
|
+
- Some agents may rate-limit or budget Bash calls separately from MCP calls.
|
|
1087
|
+
- Cloud-only agents (claude.ai, chatgpt.com) cannot use Path C at all — they have no Bash tool.
|
|
1088
|
+
|
|
1089
|
+
### Prerequisites
|
|
1090
|
+
|
|
1091
|
+
Same as **Path A-Local**:
|
|
1092
|
+
|
|
1093
|
+
- [`uv`](https://docs.astral.sh/uv/getting-started/installation/) installed on your machine
|
|
1094
|
+
- Cerefox repository cloned locally (e.g. `/Users/yourname/src/cerefox`)
|
|
1095
|
+
- `.env` configured with `CEREFOX_SUPABASE_URL`, `CEREFOX_SUPABASE_KEY` (service-role / new secret key), and your embedding API key (`OPENAI_API_KEY`)
|
|
1096
|
+
|
|
1097
|
+
Quick sanity check before pointing an agent at it:
|
|
1098
|
+
|
|
1099
|
+
```bash
|
|
1100
|
+
cd /path/to/cerefox
|
|
1101
|
+
uv run cerefox search "any query"
|
|
1102
|
+
uv run cerefox list-projects
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
If both work for you, they'll work for the agent.
|
|
1106
|
+
|
|
1107
|
+
### How to enable it for an agent
|
|
1108
|
+
|
|
1109
|
+
The pattern is the same across Claude Code, Codex CLI, opencode, OpenClaw, Hermes, and similar tools:
|
|
1110
|
+
|
|
1111
|
+
1. **Tell the agent the Cerefox checkout path** (e.g. via system prompt, project memory, or your agent's equivalent of `CLAUDE.md`).
|
|
1112
|
+
2. **Point the agent at the agent docs** in that checkout: `AGENT_GUIDE.md` and `AGENT_QUICK_REFERENCE.md`. These already describe what to read, what to write, and the audit/metadata conventions. They cover MCP usage; the CLI mapping is in `AGENT_GUIDE.md` ("Using Cerefox via the CLI").
|
|
1113
|
+
3. **Optionally**: add a one-line reminder in the agent's system prompt so the model defaults to using Cerefox proactively.
|
|
1114
|
+
|
|
1115
|
+
Example system-prompt snippet (adapt for your agent — Claude Code's `CLAUDE.md`, Codex's `AGENTS.md`, opencode's project config, etc.):
|
|
1116
|
+
|
|
1117
|
+
```
|
|
1118
|
+
You have access to a personal Cerefox knowledge base via a local CLI.
|
|
1119
|
+
|
|
1120
|
+
- Path: /path/to/cerefox (cd here before running commands)
|
|
1121
|
+
- Run any command with: uv run cerefox <subcommand>
|
|
1122
|
+
- Read AGENT_GUIDE.md and AGENT_QUICK_REFERENCE.md in that directory for
|
|
1123
|
+
conventions, metadata rules, and the MCP-tool → CLI-command mapping.
|
|
1124
|
+
Full per-flag reference: docs/guides/cli.md.
|
|
1125
|
+
|
|
1126
|
+
Identify yourself on every call:
|
|
1127
|
+
- Writes (ingest, ingest-dir): pass --author "<your-name>" --author-type agent
|
|
1128
|
+
- Reads (search, get-doc, list-versions, list-projects, metadata-search,
|
|
1129
|
+
get-audit-log): pass --requestor "<your-name>"
|
|
1130
|
+
|
|
1131
|
+
When answering questions, search Cerefox first. When the user asks you to
|
|
1132
|
+
remember something, ingest it. Cite document titles for every claim drawn
|
|
1133
|
+
from the knowledge base.
|
|
1134
|
+
```
|
|
1135
|
+
|
|
1136
|
+
### MCP tool ↔ CLI command mapping
|
|
1137
|
+
|
|
1138
|
+
The agent docs are written around MCP tool names. **CLI flag names match MCP parameter names exactly** (kebab-cased) — short forms like `--project`, `--filter`, `--count`, `--update`, `--version` are accepted as aliases. Full per-flag reference: [`docs/guides/cli.md`](cli.md).
|
|
1139
|
+
|
|
1140
|
+
| MCP tool | CLI command |
|
|
1141
|
+
|---|---|
|
|
1142
|
+
| `cerefox_search` | `uv run cerefox search "<query>" --match-count N --project-name <n> --metadata-filter '<json>' --requestor <name>` (CLI-only: `--mode`, `--alpha`, `--min-score`) |
|
|
1143
|
+
| `cerefox_ingest` (file) | `uv run cerefox ingest <path> --title <t> --project-name <n> --metadata '<json>' --update-if-exists\|--document-id <uuid> --source <s> --author <a> --author-type user\|agent` |
|
|
1144
|
+
| `cerefox_ingest` (paste) | `printf '...' \| uv run cerefox ingest --paste --title "<title>"` (same flags) |
|
|
1145
|
+
| `cerefox_get_document` | `uv run cerefox get-doc <document-id> --version-id <vid> --requestor <name>` |
|
|
1146
|
+
| `cerefox_list_versions` | `uv run cerefox list-versions <document-id> --requestor <name>` |
|
|
1147
|
+
| `cerefox_list_projects` | `uv run cerefox list-projects --requestor <name>` |
|
|
1148
|
+
| `cerefox_list_metadata_keys` | `uv run cerefox list-metadata-keys` |
|
|
1149
|
+
| `cerefox_metadata_search` | `uv run cerefox metadata-search --metadata-filter '<json>' --project-name <n> --requestor <name>` |
|
|
1150
|
+
| `cerefox_get_audit_log` | `uv run cerefox get-audit-log --document-id <id> --author <a> --operation <op> --since <iso> --until <iso> --limit N --json --requestor <name>` |
|
|
1151
|
+
|
|
1152
|
+
### Path C verification prompts
|
|
1153
|
+
|
|
1154
|
+
After pointing your agent at the repo, ask it:
|
|
1155
|
+
|
|
1156
|
+
> "Run a Cerefox search for 'second brain'. What did you find?"
|
|
1157
|
+
> Expected: agent runs `uv run cerefox search "second brain"` via its Bash tool and reports results.
|
|
1158
|
+
|
|
1159
|
+
> "Save a note titled 'Test Note' to Cerefox with the content '# Test\nThis is a Path C test.'"
|
|
1160
|
+
> Expected: agent runs `cerefox ingest --paste --title "Test Note"` (or equivalent) and reports the new document ID.
|
|
1161
|
+
|
|
1162
|
+
> "List my Cerefox projects."
|
|
1163
|
+
> Expected: agent runs `uv run cerefox list-projects`.
|
|
1164
|
+
|
|
1165
|
+
### Caveats
|
|
1166
|
+
|
|
1167
|
+
- **Privilege level**: the CLI uses the **service-role key** (`CEREFOX_SUPABASE_KEY`), which bypasses Row Level Security. An agent with Bash access has the same full read/write power you do. Only enable Path C for agents you trust to act on your behalf — the same trust level you'd grant Cursor/Claude Code for editing your source code.
|
|
1168
|
+
- **Audit attribution**: Path C records `access_path = "cli"` in usage logs, distinct from `"local-mcp"` / `"remote-mcp"`. **Agents must set `--author <name> --author-type agent` on writes and `--requestor <name>` on reads** (or rely on `CEREFOX_AUTHOR_NAME` / `CEREFOX_AUTHOR_TYPE` / `CEREFOX_REQUESTOR_NAME` env vars). Without these flags, writes attribute to `"unknown"` / `"user"`, which under-reports agent activity. See the 2026-05-18 Decision Log Q2 entry for the design rationale (`author_type` is caller-declared on ambiguous channels — CLI and Edge Functions — but `access_path` is always derived from the code layer).
|
|
1169
|
+
- **Soft-delete is reachable; purge and restore are not** — by design. `cerefox delete-doc` is exposed on the CLI and sends documents to trash with an audit entry. **Permanent purge** (irreversible) and **restore from trash** (un-doing a destructive action) are intentionally web-UI-only and require human-in-the-loop confirmation. If an agent on Path C decides to delete content, it should surface that to the user explicitly so they can review and either restore or commit. See [`access-paths.md` → Destructive operations and the trust model](access-paths.md#destructive-operations-and-the-trust-model) for the full rationale and contributor guidance.
|
|
1170
|
+
- **Cross-doc links in content you ingest** become clickable when the user views them in the Cerefox web UI. Author them as `[Text](uuid)` (most stable), `[Text](docs/path.md)` (repo files), or `[Text](<Title With Spaces>)` (angle-bracket form — bare spaces break markdown). See [`AGENT_GUIDE.md` → "Writing linkable content"](../../AGENT_GUIDE.md#writing-linkable-content) for the full set of rules.
|
|
1171
|
+
- **One repo per machine**: the agent needs your checkout — there's no "Path C without a local clone". If you skip the local install entirely, Path A-Remote or Path B is the only option.
|
|
1172
|
+
- **No sandboxing beyond the agent's existing Bash sandbox**: the CLI is just shell. If your agent's tool framework restricts which commands run, allowlist `uv run cerefox …` explicitly.
|
|
1173
|
+
|
|
1174
|
+
### Path C is configuration-free, but here's the per-agent footprint
|
|
1175
|
+
|
|
1176
|
+
| Agent | Where to mention the Cerefox path |
|
|
1177
|
+
|---|---|
|
|
1178
|
+
| Claude Code | `CLAUDE.md` in the project, or `~/.claude/CLAUDE.md` globally. No MCP entry needed. |
|
|
1179
|
+
| OpenAI Codex CLI | `AGENTS.md` or the project's instructions file. |
|
|
1180
|
+
| opencode | Project config / agent system prompt. |
|
|
1181
|
+
| OpenClaw, Hermes, custom local agents | Whatever the tool's system-prompt / memory mechanism is. |
|
|
1182
|
+
|
|
1183
|
+
There is nothing Cerefox-specific to install for the agent itself — just the repo + your `.env`.
|
|
1184
|
+
|
|
1185
|
+
---
|
|
1186
|
+
|
|
1187
|
+
## Custom agents (Python SDK)
|
|
1188
|
+
|
|
1189
|
+
Use the Cerefox Python client directly for scripted or embedded agents:
|
|
1190
|
+
|
|
1191
|
+
```python
|
|
1192
|
+
from cerefox.config import Settings
|
|
1193
|
+
from cerefox.db.client import CerefoxClient
|
|
1194
|
+
from cerefox.embeddings.cloud import CloudEmbedder
|
|
1195
|
+
from cerefox.retrieval.search import SearchClient
|
|
1196
|
+
|
|
1197
|
+
settings = Settings() # reads from .env
|
|
1198
|
+
client = CerefoxClient(settings)
|
|
1199
|
+
embedder = CloudEmbedder(
|
|
1200
|
+
api_key=settings.get_embedder_api_key(),
|
|
1201
|
+
base_url=settings.get_embedder_base_url(),
|
|
1202
|
+
model=settings.get_embedder_model(),
|
|
1203
|
+
dimensions=settings.get_embedder_dimensions(),
|
|
1204
|
+
)
|
|
1205
|
+
sc = SearchClient(client, embedder, settings)
|
|
1206
|
+
|
|
1207
|
+
resp = sc.search_docs("what did I write about Rust?", match_count=5)
|
|
1208
|
+
for hit in resp.results:
|
|
1209
|
+
print(f"[{hit.best_score:.2f}] {hit.doc_title}")
|
|
1210
|
+
print(hit.full_content[:400])
|
|
1211
|
+
```
|
|
1212
|
+
|
|
1213
|
+
---
|
|
1214
|
+
|
|
1215
|
+
## Keeping both paths in sync
|
|
1216
|
+
|
|
1217
|
+
Both paths use the same Postgres RPCs and the same stored embeddings, but embed queries
|
|
1218
|
+
independently. If you change the embedding model, **update both paths** before searching:
|
|
1219
|
+
|
|
1220
|
+
1. Update `.env` + run `cerefox reindex` (re-embeds stored chunks via Python)
|
|
1221
|
+
2. Update the TypeScript constants in `supabase/functions/*/index.ts` + redeploy Edge Functions
|
|
1222
|
+
|
|
1223
|
+
See `docs/guides/configuration.md` → "Changing the embedding model" for the full procedure.
|
|
1224
|
+
|
|
1225
|
+
---
|
|
1226
|
+
|
|
1227
|
+
## MCP tool reference
|
|
1228
|
+
|
|
1229
|
+
### `cerefox_search`
|
|
1230
|
+
|
|
1231
|
+
Search the knowledge base. Returns complete documents ranked by hybrid (FTS + semantic) relevance.
|
|
1232
|
+
|
|
1233
|
+
| Parameter | Type | Default | Description |
|
|
1234
|
+
|-----------|------|---------|-------------|
|
|
1235
|
+
| `query` | string | required | Natural-language search query |
|
|
1236
|
+
| `match_count` | integer | 5 | Maximum **documents** to return |
|
|
1237
|
+
| `project_name` | string | optional | Filter to a specific project |
|
|
1238
|
+
|
|
1239
|
+
Each result includes `doc_title`, `best_score`, `full_content`, `chunk_count`, `total_chars`, and `is_partial`. When `is_partial` is true, the document exceeded the small-to-big threshold: `full_content` contains the best-matching chunks and their neighbours rather than the whole document. The heading for such results includes a `— partial (N of M chars)` annotation. Use `cerefox_get_document` to retrieve the full text when needed.
|
|
1240
|
+
|
|
1241
|
+
### `cerefox_ingest`
|
|
1242
|
+
|
|
1243
|
+
Save a note or document to the knowledge base.
|
|
1244
|
+
|
|
1245
|
+
| Parameter | Type | Default | Description |
|
|
1246
|
+
|-----------|------|---------|-------------|
|
|
1247
|
+
| `title` | string | required | Document title |
|
|
1248
|
+
| `content` | string | required | Markdown content |
|
|
1249
|
+
| `document_id` | string | optional | UUID of an existing document to update. When provided, updates that document directly regardless of `update_if_exists`. Returns an error if the document does not exist. Workflow: `cerefox_search` → note `[id: ...]` → pass here. |
|
|
1250
|
+
| `project_name` | string | optional | Assign to a project (created if absent) |
|
|
1251
|
+
| `source` | string | `"agent"` | Origin label |
|
|
1252
|
+
| `metadata` | object | `{}` | Arbitrary JSON metadata |
|
|
1253
|
+
| `update_if_exists` | boolean | `false` | When true, update an existing document with the same title instead of creating a new one. The previous version is archived automatically. Content is re-indexed only if it changed. Ignored when `document_id` is provided. |
|
|
1254
|
+
|
|
1255
|
+
### `cerefox_list_metadata_keys`
|
|
1256
|
+
|
|
1257
|
+
No parameters. Returns all distinct metadata keys currently in use across documents, with document counts and up to 5 example values per key.
|
|
1258
|
+
|
|
1259
|
+
### `cerefox_get_document`
|
|
1260
|
+
|
|
1261
|
+
Retrieve the full reconstructed content of a document. Pass `version_id` to retrieve an archived version; omit it for the current version. Version UUIDs are returned by `cerefox_list_versions`.
|
|
1262
|
+
|
|
1263
|
+
| Parameter | Type | Default | Description |
|
|
1264
|
+
|-----------|------|---------|-------------|
|
|
1265
|
+
| `document_id` | string | required | UUID of the document to retrieve |
|
|
1266
|
+
| `version_id` | string | optional | UUID of a specific archived version; omit for current |
|
|
1267
|
+
|
|
1268
|
+
### `cerefox_list_versions`
|
|
1269
|
+
|
|
1270
|
+
List all archived versions of a document, newest first. Returns `version_id` (use with `cerefox_get_document`), `version_number`, `source`, `chunk_count`, `total_chars`, and `created_at`.
|
|
1271
|
+
|
|
1272
|
+
| Parameter | Type | Default | Description |
|
|
1273
|
+
|-----------|------|---------|-------------|
|
|
1274
|
+
| `document_id` | string | required | UUID of the document whose version history to list |
|
|
1275
|
+
|
|
1276
|
+
---
|
|
1277
|
+
|
|
1278
|
+
## RPC reference
|
|
1279
|
+
|
|
1280
|
+
All RPCs are defined in `src/cerefox/db/rpcs.sql`.
|
|
1281
|
+
|
|
1282
|
+
### Search RPCs
|
|
1283
|
+
|
|
1284
|
+
Every chunk-level RPC returns these fields:
|
|
1285
|
+
|
|
1286
|
+
| Field | Type | Description |
|
|
1287
|
+
|-------|------|-------------|
|
|
1288
|
+
| `chunk_id` | UUID | ID of the matching chunk |
|
|
1289
|
+
| `document_id` | UUID | ID of the parent document |
|
|
1290
|
+
| `chunk_index` | INT | Position within the document |
|
|
1291
|
+
| `title` | TEXT | Chunk heading (H1/H2/H3) |
|
|
1292
|
+
| `content` | TEXT | Full chunk text |
|
|
1293
|
+
| `heading_path` | TEXT[] | Breadcrumb: e.g. `["Doc Title", "Section", "Sub"]` |
|
|
1294
|
+
| `heading_level` | INT | 0–3 |
|
|
1295
|
+
| `score` | FLOAT | Relevance score (higher = more relevant) |
|
|
1296
|
+
| `doc_title` | TEXT | Parent document title |
|
|
1297
|
+
| `doc_source` | TEXT | Origin: `"file"`, `"paste"`, `"agent"` |
|
|
1298
|
+
| `doc_project_ids` | UUID[] | Project UUIDs assigned to the document |
|
|
1299
|
+
| `doc_metadata` | JSONB | Document metadata |
|
|
1300
|
+
|
|
1301
|
+
#### `cerefox_fts_search`
|
|
1302
|
+
|
|
1303
|
+
Full-text keyword search. Does not require an embedding model.
|
|
1304
|
+
|
|
1305
|
+
| Parameter | Type | Default | Description |
|
|
1306
|
+
|-----------|------|---------|-------------|
|
|
1307
|
+
| `p_query_text` | TEXT | required | Keyword query |
|
|
1308
|
+
| `p_match_count` | INT | 10 | Results to return |
|
|
1309
|
+
| `p_project_id` | UUID | null | Filter by project |
|
|
1310
|
+
|
|
1311
|
+
#### `cerefox_semantic_search`
|
|
1312
|
+
|
|
1313
|
+
Vector similarity search. Requires a pre-computed query embedding.
|
|
1314
|
+
|
|
1315
|
+
| Parameter | Type | Default | Description |
|
|
1316
|
+
|-----------|------|---------|-------------|
|
|
1317
|
+
| `p_query_embedding` | VECTOR(768) | required | Query embedding |
|
|
1318
|
+
| `p_match_count` | INT | 10 | Results to return |
|
|
1319
|
+
| `p_use_upgrade` | BOOL | false | Use upgrade embedding column |
|
|
1320
|
+
| `p_project_id` | UUID | null | Filter by project |
|
|
1321
|
+
| `p_min_score` | FLOAT | 0.0 | Minimum cosine similarity |
|
|
1322
|
+
|
|
1323
|
+
#### `cerefox_hybrid_search`
|
|
1324
|
+
|
|
1325
|
+
Combines FTS and semantic search via linear alpha blending. Two overloads (with/without `p_project_id`).
|
|
1326
|
+
|
|
1327
|
+
| Parameter | Type | Default | Description |
|
|
1328
|
+
|-----------|------|---------|-------------|
|
|
1329
|
+
| `p_query_text` | TEXT | required | Query string for FTS |
|
|
1330
|
+
| `p_query_embedding` | VECTOR(768) | required | Query embedding |
|
|
1331
|
+
| `p_match_count` | INT | 10 | Results to return |
|
|
1332
|
+
| `p_alpha` | FLOAT | 0.7 | Semantic weight (0=FTS only, 1=semantic only) |
|
|
1333
|
+
| `p_use_upgrade` | BOOL | false | Use upgrade embedding column |
|
|
1334
|
+
| `p_project_id` | UUID | null | Filter by project |
|
|
1335
|
+
| `p_min_score` | FLOAT | 0.0 | Minimum cosine similarity |
|
|
1336
|
+
|
|
1337
|
+
#### `cerefox_search_docs`
|
|
1338
|
+
|
|
1339
|
+
Document-level search. Runs hybrid search internally, deduplicates by document, then returns up to
|
|
1340
|
+
`p_match_count` **distinct documents** with their full reconstructed content. **This is the
|
|
1341
|
+
recommended RPC for agent use** — agents receive complete notes, not isolated chunks.
|
|
1342
|
+
|
|
1343
|
+
| Parameter | Type | Default | Description |
|
|
1344
|
+
|-----------|------|---------|-------------|
|
|
1345
|
+
| `p_query_text` | TEXT | required | Query string for FTS |
|
|
1346
|
+
| `p_query_embedding` | VECTOR(768) | required | Query embedding |
|
|
1347
|
+
| `p_match_count` | INT | 5 | Max documents to return |
|
|
1348
|
+
| `p_alpha` | FLOAT | 0.7 | Semantic weight |
|
|
1349
|
+
| `p_project_id` | UUID | null | Filter by project |
|
|
1350
|
+
| `p_min_score` | FLOAT | 0.0 | Minimum cosine similarity |
|
|
1351
|
+
| `p_small_to_big_threshold` | INT | 40000 | Documents larger than this return matched chunks + neighbours instead of the full document. Set to `0` to always return full content. Change the DEFAULT in `rpcs.sql` to apply server-wide. |
|
|
1352
|
+
| `p_context_window` | INT | 1 | Neighbour chunks on each side of each matched chunk. `1` → up to 3 contiguous chunks per hit. `0` → matched chunks only. |
|
|
1353
|
+
|
|
1354
|
+
Returns: `document_id`, `doc_title`, `doc_source`, `doc_metadata`, `doc_project_ids`,
|
|
1355
|
+
`best_score`, `best_chunk_heading_path`, `full_content`, `chunk_count`, `total_chars`,
|
|
1356
|
+
`doc_updated_at`, `version_count`, `is_partial`.
|
|
1357
|
+
|
|
1358
|
+
`is_partial` is `TRUE` when the document exceeded `p_small_to_big_threshold` — in that
|
|
1359
|
+
case `full_content` contains matched chunks + up to `p_context_window` neighbours on each
|
|
1360
|
+
side, deduplicated and sorted by `chunk_index`. `total_chars` always reflects the full
|
|
1361
|
+
document size regardless of whether the result is partial.
|
|
1362
|
+
|
|
1363
|
+
---
|
|
1364
|
+
|
|
1365
|
+
### Document RPCs
|
|
1366
|
+
|
|
1367
|
+
#### `cerefox_reconstruct_doc`
|
|
1368
|
+
|
|
1369
|
+
Fetch a full document by ID, concatenating all chunks in order.
|
|
1370
|
+
|
|
1371
|
+
| Parameter | Type | Description |
|
|
1372
|
+
|-----------|------|-------------|
|
|
1373
|
+
| `p_document_id` | UUID | Document to reconstruct |
|
|
1374
|
+
|
|
1375
|
+
Returns: `document_id`, `doc_title`, `doc_source`, `doc_metadata`, `full_content`,
|
|
1376
|
+
`chunk_count`, `total_chars`
|
|
1377
|
+
|
|
1378
|
+
#### `cerefox_context_expand`
|
|
1379
|
+
|
|
1380
|
+
Small-to-big retrieval: given a set of chunk IDs, returns those chunks **plus their immediate
|
|
1381
|
+
neighbours** (±`p_window_size` chunks within the same document).
|
|
1382
|
+
|
|
1383
|
+
| Parameter | Type | Default | Description |
|
|
1384
|
+
|-----------|------|---------|-------------|
|
|
1385
|
+
| `p_chunk_ids` | UUID[] | required | Array of chunk UUIDs from search results |
|
|
1386
|
+
| `p_window_size` | INT | 1 | Chunks to expand in each direction |
|
|
1387
|
+
|
|
1388
|
+
Returns: `chunk_id`, `document_id`, `chunk_index`, `title`, `content`, `heading_path`,
|
|
1389
|
+
`heading_level`, `doc_title`, `is_seed` (TRUE for the original seed chunks)
|
|
1390
|
+
|
|
1391
|
+
#### `cerefox_save_note`
|
|
1392
|
+
|
|
1393
|
+
Create a document record directly. The note is stored but **not embedded** — use `cerefox-ingest`
|
|
1394
|
+
Edge Function instead for notes that need to be immediately searchable.
|
|
1395
|
+
|
|
1396
|
+
| Parameter | Type | Default | Description |
|
|
1397
|
+
|-----------|------|---------|-------------|
|
|
1398
|
+
| `p_title` | TEXT | required | Note title |
|
|
1399
|
+
| `p_content` | TEXT | required | Markdown content |
|
|
1400
|
+
| `p_source` | TEXT | `'agent'` | Origin label |
|
|
1401
|
+
| `p_project_id` | UUID | null | Project to assign |
|
|
1402
|
+
| `p_metadata` | JSONB | `{}` | Metadata (agent name, tags, etc.) |
|
|
1403
|
+
|
|
1404
|
+
Returns: `id`, `title`, `created_at`
|
|
1405
|
+
|
|
1406
|
+
---
|
|
1407
|
+
|
|
1408
|
+
### Metadata RPCs
|
|
1409
|
+
|
|
1410
|
+
#### `cerefox_list_metadata_keys`
|
|
1411
|
+
|
|
1412
|
+
No parameters. Returns all distinct metadata keys currently in use across documents.
|
|
1413
|
+
|
|
1414
|
+
| Column | Type | Description |
|
|
1415
|
+
|--------|------|-------------|
|
|
1416
|
+
| `key` | TEXT | Metadata key name |
|
|
1417
|
+
| `doc_count` | BIGINT | Number of documents using this key |
|
|
1418
|
+
| `example_values` | TEXT[] | Up to 5 sample values |
|
|
1419
|
+
|
|
1420
|
+
This RPC derives keys from actual `doc_metadata` JSONB — no separate registry table.
|
|
1421
|
+
|
|
1422
|
+
---
|
|
1423
|
+
|
|
1424
|
+
## Response size
|
|
1425
|
+
|
|
1426
|
+
Cerefox's default `max_response_bytes = 200000` is a safety ceiling; small-to-big retrieval
|
|
1427
|
+
keeps individual results compact so this limit is rarely reached in practice. If your MCP
|
|
1428
|
+
client has a lower context limit, reduce it via `CEREFOX_MAX_RESPONSE_BYTES` in your `.env`.
|