@cerefox/memory 0.10.1 → 0.10.2

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.
@@ -7184,7 +7184,7 @@ var exports_meta = {};
7184
7184
  __export(exports_meta, {
7185
7185
  PKG_VERSION: () => PKG_VERSION
7186
7186
  });
7187
- var PKG_VERSION = "0.10.1";
7187
+ var PKG_VERSION = "0.10.2";
7188
7188
  var init_meta = () => {};
7189
7189
 
7190
7190
  // ../../node_modules/.bun/tslib@2.8.1/node_modules/tslib/tslib.js
@@ -68198,26 +68198,26 @@ function collectNodes() {
68198
68198
  nodes.sort((a, b) => a.path.localeCompare(b.path));
68199
68199
  return nodes;
68200
68200
  }
68201
- function bashScript(nodes) {
68201
+ function bashScript(nodes, prog, fn) {
68202
68202
  const candCases = nodes.map((n) => ` "${n.path}") echo "${n.candidates.join(" ")}" ;;`).join(`
68203
68203
  `);
68204
68204
  const pathPatterns = nodes.filter((n) => n.path !== "").map((n) => `"${n.path}"`).join("|");
68205
68205
  return `# Cerefox bash completion. Source from ~/.bashrc:
68206
- # source <(cerefox completion bash)
68206
+ # source <(${prog} completion bash)
68207
68207
  #
68208
- _cerefox_candidates() {
68208
+ _${fn}_candidates() {
68209
68209
  case "$1" in
68210
68210
  ${candCases}
68211
68211
  *) echo "--help" ;;
68212
68212
  esac
68213
68213
  }
68214
- _cerefox_is_path() {
68214
+ _${fn}_is_path() {
68215
68215
  case "$1" in
68216
68216
  ${pathPatterns}) return 0 ;;
68217
68217
  *) return 1 ;;
68218
68218
  esac
68219
68219
  }
68220
- _cerefox_completion() {
68220
+ _${fn}_completion() {
68221
68221
  local cur path trial w i
68222
68222
  COMPREPLY=()
68223
68223
  cur="\${COMP_WORDS[COMP_CWORD]}"
@@ -68227,39 +68227,39 @@ _cerefox_completion() {
68227
68227
  w="\${COMP_WORDS[$i]}"
68228
68228
  case "$w" in -*) break ;; esac
68229
68229
  if [ -z "$path" ]; then trial="$w"; else trial="$path $w"; fi
68230
- if _cerefox_is_path "$trial"; then
68230
+ if _${fn}_is_path "$trial"; then
68231
68231
  path="$trial"; i=$((i + 1))
68232
68232
  else
68233
68233
  break
68234
68234
  fi
68235
68235
  done
68236
- COMPREPLY=( $(compgen -W "$(_cerefox_candidates "$path")" -- "$cur") )
68236
+ COMPREPLY=( $(compgen -W "$(_${fn}_candidates "$path")" -- "$cur") )
68237
68237
  return 0
68238
68238
  }
68239
- complete -F _cerefox_completion cerefox
68239
+ complete -F _${fn}_completion ${prog}
68240
68240
  `;
68241
68241
  }
68242
- function zshScript(nodes) {
68242
+ function zshScript(nodes, prog, fn) {
68243
68243
  const candCases = nodes.map((n) => ` "${n.path}") REPLY="${n.candidates.join(" ")}" ;;`).join(`
68244
68244
  `);
68245
68245
  const pathPatterns = nodes.filter((n) => n.path !== "").map((n) => `"${n.path}"`).join("|");
68246
- return `#compdef cerefox
68246
+ return `#compdef ${prog}
68247
68247
  # Cerefox zsh completion. Save and source from ~/.zshrc:
68248
- # source <(cerefox completion zsh)
68248
+ # source <(${prog} completion zsh)
68249
68249
  #
68250
- _cerefox_candidates() {
68250
+ _${fn}_candidates() {
68251
68251
  case "$1" in
68252
68252
  ${candCases}
68253
68253
  *) REPLY="--help" ;;
68254
68254
  esac
68255
68255
  }
68256
- _cerefox_is_path() {
68256
+ _${fn}_is_path() {
68257
68257
  case "$1" in
68258
68258
  ${pathPatterns}) return 0 ;;
68259
68259
  *) return 1 ;;
68260
68260
  esac
68261
68261
  }
68262
- _cerefox() {
68262
+ _${fn}() {
68263
68263
  local path trial w i REPLY
68264
68264
  path=""
68265
68265
  i=2
@@ -68267,13 +68267,13 @@ _cerefox() {
68267
68267
  w="\${words[i]}"
68268
68268
  case "$w" in -*) break ;; esac
68269
68269
  if [[ -z "$path" ]]; then trial="$w"; else trial="$path $w"; fi
68270
- if _cerefox_is_path "$trial"; then
68270
+ if _${fn}_is_path "$trial"; then
68271
68271
  path="$trial"; (( i++ ))
68272
68272
  else
68273
68273
  break
68274
68274
  fi
68275
68275
  done
68276
- _cerefox_candidates "$path"
68276
+ _${fn}_candidates "$path"
68277
68277
  compadd -- \${=REPLY}
68278
68278
  }
68279
68279
  # Self-bootstrap the completion system if no \`compinit\` has run yet (e.g. this
@@ -68282,23 +68282,23 @@ _cerefox() {
68282
68282
  if ! whence compdef >/dev/null 2>&1; then
68283
68283
  autoload -Uz compinit && compinit
68284
68284
  fi
68285
- compdef _cerefox cerefox
68285
+ compdef _${fn} ${prog}
68286
68286
  `;
68287
68287
  }
68288
- function fishScript(nodes) {
68288
+ function fishScript(nodes, prog, fn) {
68289
68289
  const candCases = nodes.map((n) => ` case "${n.path}"
68290
68290
  echo "${n.candidates.join(" ")}"`).join(`
68291
68291
  `);
68292
68292
  const pathList = nodes.filter((n) => n.path !== "").map((n) => `"${n.path}"`).join(" ");
68293
- return `# Cerefox fish completion. Save to ~/.config/fish/completions/cerefox.fish
68294
- function __cerefox_candidates
68293
+ return `# Cerefox fish completion. Save to ~/.config/fish/completions/${prog}.fish
68294
+ function __${fn}_candidates
68295
68295
  switch "$argv[1]"
68296
68296
  ${candCases}
68297
68297
  case '*'
68298
68298
  echo "--help"
68299
68299
  end
68300
68300
  end
68301
- function __cerefox_is_path
68301
+ function __${fn}_is_path
68302
68302
  for p in ${pathList}
68303
68303
  if test "$argv[1]" = "$p"
68304
68304
  return 0
@@ -68306,7 +68306,7 @@ function __cerefox_is_path
68306
68306
  end
68307
68307
  return 1
68308
68308
  end
68309
- function __cerefox_complete
68309
+ function __${fn}_complete
68310
68310
  set -l tokens (commandline -opc)
68311
68311
  set -l path ""
68312
68312
  set -l i 2
@@ -68321,27 +68321,35 @@ function __cerefox_complete
68321
68321
  else
68322
68322
  set trial "$path $w"
68323
68323
  end
68324
- if __cerefox_is_path "$trial"
68324
+ if __${fn}_is_path "$trial"
68325
68325
  set path "$trial"
68326
68326
  set i (math $i + 1)
68327
68327
  else
68328
68328
  break
68329
68329
  end
68330
68330
  end
68331
- string split ' ' -- (__cerefox_candidates "$path")
68331
+ string split ' ' -- (__${fn}_candidates "$path")
68332
68332
  end
68333
- complete -c cerefox -f -a '(__cerefox_complete)'
68333
+ complete -c ${prog} -f -a '(__${fn}_complete)'
68334
68334
  `;
68335
68335
  }
68336
+ function progName() {
68337
+ return buildProgram().name();
68338
+ }
68339
+ function fnId(prog) {
68340
+ return prog.replace(/[^a-zA-Z0-9]/g, "_");
68341
+ }
68336
68342
  function scriptFor(shell) {
68337
68343
  const nodes = collectNodes();
68344
+ const prog = progName();
68345
+ const fn = fnId(prog);
68338
68346
  switch (shell) {
68339
68347
  case "bash":
68340
- return bashScript(nodes);
68348
+ return bashScript(nodes, prog, fn);
68341
68349
  case "zsh":
68342
- return zshScript(nodes);
68350
+ return zshScript(nodes, prog, fn);
68343
68351
  case "fish":
68344
- return fishScript(nodes);
68352
+ return fishScript(nodes, prog, fn);
68345
68353
  }
68346
68354
  }
68347
68355
  function detectShell() {
@@ -68350,8 +68358,12 @@ function detectShell() {
68350
68358
  return sh;
68351
68359
  return null;
68352
68360
  }
68353
- var RC_BEGIN = "# >>> cerefox shell completion (managed by `cerefox completion install`) >>>";
68354
- var RC_END = "# <<< cerefox shell completion <<<";
68361
+ function rcBeginFor(prog) {
68362
+ return `# >>> ${prog} shell completion (managed by \`${prog} completion install\`) >>>`;
68363
+ }
68364
+ function rcEndFor(prog) {
68365
+ return `# <<< ${prog} shell completion <<<`;
68366
+ }
68355
68367
  async function installMode(options) {
68356
68368
  const shell = options.shell ?? detectShell();
68357
68369
  if (!shell) {
@@ -68361,21 +68373,24 @@ async function installMode(options) {
68361
68373
  throw userError(`Unsupported --shell "${shell}". Use bash, zsh, or fish.`);
68362
68374
  }
68363
68375
  const home = homedir3();
68364
- const scriptPath = join3(home, `.cerefox-completion.${shell}`);
68376
+ const prog = progName();
68377
+ const rcBegin = rcBeginFor(prog);
68378
+ const rcEnd = rcEndFor(prog);
68379
+ const scriptPath = join3(home, `.${prog}-completion.${shell}`);
68365
68380
  writeFileSync2(scriptPath, scriptFor(shell), "utf8");
68366
68381
  println(c.green(`✓ Wrote completion script: ${scriptPath}`));
68367
68382
  if (shell === "fish") {
68368
- println(c.dim(" For fish, also copy it into ~/.config/fish/completions/cerefox.fish (or `source` it)."));
68383
+ println(c.dim(` For fish, also copy it into ~/.config/fish/completions/${prog}.fish (or \`source\` it).`));
68369
68384
  return;
68370
68385
  }
68371
68386
  const rcPath = join3(home, shell === "zsh" ? ".zshrc" : ".bashrc");
68372
68387
  const sourceLine = `[ -s "${scriptPath}" ] && source "${scriptPath}"`;
68373
- const block = `${RC_BEGIN}
68388
+ const block = `${rcBegin}
68374
68389
  ${sourceLine}
68375
- ${RC_END}
68390
+ ${rcEnd}
68376
68391
  `;
68377
68392
  const existing = existsSync3(rcPath) ? readFileSync3(rcPath, "utf8") : "";
68378
- if (existing.includes(RC_BEGIN)) {
68393
+ if (existing.includes(rcBegin)) {
68379
68394
  println(c.dim(` ${rcPath} already sources the completion (left as-is).`));
68380
68395
  } else {
68381
68396
  const interactive = process.stdout.isTTY && !options.yes;
@@ -69604,6 +69619,12 @@ function defaultCerefoxEntry() {
69604
69619
  args: ["-y", "--package=@cerefox/memory", "cerefox", "mcp"]
69605
69620
  };
69606
69621
  }
69622
+ function localCerefoxEntry() {
69623
+ return {
69624
+ command: process.env.CEREFOX_LOCAL_CMD || "cerefox-local",
69625
+ args: ["mcp"]
69626
+ };
69627
+ }
69607
69628
  function claudeCodeUserConfigPath() {
69608
69629
  return join4(homedir4(), ".claude.json");
69609
69630
  }
@@ -69617,8 +69638,7 @@ function claudeDesktopConfigPath() {
69617
69638
  }
69618
69639
  return join4(home, ".config", "Claude", "claude_desktop_config.json");
69619
69640
  }
69620
- function claudeCodeDelegated() {
69621
- const entry = defaultCerefoxEntry();
69641
+ function claudeCodeDelegated(entry) {
69622
69642
  return {
69623
69643
  cmd: "claude",
69624
69644
  args: ["mcp", "add", "cerefox", "--scope", "user", "--", entry.command, ...entry.args]
@@ -69684,7 +69704,7 @@ function writeMcpConfig(writer, opts = {}) {
69684
69704
  return directWrite(writer, writer.configPath, opts);
69685
69705
  }
69686
69706
  function directWrite(writer, configPath, opts) {
69687
- const entry = writer.buildServerEntry();
69707
+ const entry = opts.entry ?? writer.buildServerEntry();
69688
69708
  const format = writer.format ?? "json";
69689
69709
  if (!opts.dryRun)
69690
69710
  mkdirSync2(dirname(configPath), { recursive: true });
@@ -69725,8 +69745,8 @@ function delegatedWrite(writer, opts) {
69725
69745
  if (!writer.delegated) {
69726
69746
  throw new Error(`${writer.label}: kind=delegated but no delegated() factory`);
69727
69747
  }
69728
- const { cmd, args } = writer.delegated();
69729
- const entry = writer.buildServerEntry();
69748
+ const entry = opts.entry ?? writer.buildServerEntry();
69749
+ const { cmd, args } = writer.delegated(entry);
69730
69750
  const delegatedCommand = `${cmd} ${args.join(" ")}`;
69731
69751
  if (opts.dryRun) {
69732
69752
  return {
@@ -69771,7 +69791,8 @@ function action6(options) {
69771
69791
  const result = writeMcpConfig(writer, {
69772
69792
  customPath: options.configPath,
69773
69793
  noBackup: !options.backup,
69774
- dryRun: options.dryRun
69794
+ dryRun: options.dryRun,
69795
+ entry: options.local ? localCerefoxEntry() : undefined
69775
69796
  });
69776
69797
  if (options.json) {
69777
69798
  printJson(result);
@@ -69815,7 +69836,7 @@ function restartHint(id) {
69815
69836
  }
69816
69837
  }
69817
69838
  function registerConfigureAgent(program2) {
69818
- program2.command("configure-agent").description("Write the MCP server config for a supported client.").requiredOption("-t, --tool <client>", "Target client: claude-code, claude-desktop, cursor, codex, gemini.").option("--config-path <path>", "Override the default config-file path.").option("--no-backup", "Skip the .pre-cerefox.bak backup of any existing config.").option("--dry-run", "Print the planned write without modifying any file.").option("--json", "Emit JSON describing the result.").action(action6);
69839
+ program2.command("configure-agent").description("Write the MCP server config for a supported client.").requiredOption("-t, --tool <client>", "Target client: claude-code, claude-desktop, cursor, codex, gemini.").option("--config-path <path>", "Override the default config-file path.").option("--no-backup", "Skip the .pre-cerefox.bak backup of any existing config.").option("--dry-run", "Print the planned write without modifying any file.").option("--json", "Emit JSON describing the result.").option("--local", "Wire the local/self-hosted backend (`cerefox-local mcp`) instead of npx. Used by `cerefox-local configure-agent`.").action(action6);
69819
69840
  }
69820
69841
 
69821
69842
  // src/cli/commands/delete-doc.ts
@@ -76519,7 +76540,7 @@ async function action28(query, options) {
76519
76540
  const matchCount = parsePositiveInt(options.matchCount, "--match-count", 5);
76520
76541
  const alpha = parseFloat01(options.alpha, "--alpha", 0.7);
76521
76542
  const minScore = parseFloat01(options.minScore, "--min-score", getMinSearchScore());
76522
- const maxBytes = parseNonNegativeInt(options.maxBytes, "--max-bytes", 200000);
76543
+ const maxBytes = parseNonNegativeInt(options.maxBytes, "--max-bytes", getMaxResponseBytes());
76523
76544
  const mode = options.mode ?? "docs";
76524
76545
  if (!["docs", "hybrid", "fts"].includes(mode)) {
76525
76546
  throw userError(`--mode "${mode}": expected "docs", "hybrid", or "fts".`);
@@ -76664,7 +76685,7 @@ async function action28(query, options) {
76664
76685
  }
76665
76686
  }
76666
76687
  function registerSearch(program2) {
76667
- program2.command("search").description("Search the knowledge base (hybrid FTS + semantic).").argument("<query>", "Natural-language search query.").option("-c, --match-count <n>", "Maximum number of documents to return.", "5").option("-p, --project-name <name>", "Filter results to a specific project.").option("-f, --metadata-filter <json>", "JSON containment filter; only docs whose metadata contains ALL pairs are returned.").option("--mode <mode>", "Search mode: docs (default), hybrid, fts.", "docs").option("--alpha <float>", "Semantic weight 0..1 (default: 0.7).", "0.7").option("--min-score <float>", "Minimum cosine similarity threshold (default: CEREFOX_MIN_SEARCH_SCORE or 0.5).").option("--max-bytes <n>", "Response size budget in bytes.", "200000").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").option("--only-metadata", "List matching docs (id, score, chunks, chars, partial/full) WITHOUT their content — like the web UI's collapsed result list. Grab a [id:…] then `cerefox document get <id>`.").action(action28);
76688
+ program2.command("search").description("Search the knowledge base (hybrid FTS + semantic).").argument("<query>", "Natural-language search query.").option("-c, --match-count <n>", "Maximum number of documents to return.", "5").option("-p, --project-name <name>", "Filter results to a specific project.").option("-f, --metadata-filter <json>", "JSON containment filter; only docs whose metadata contains ALL pairs are returned.").option("--mode <mode>", "Search mode: docs (default), hybrid, fts.", "docs").option("--alpha <float>", "Semantic weight 0..1 (default: 0.7).", "0.7").option("--min-score <float>", "Minimum cosine similarity threshold (default: CEREFOX_MIN_SEARCH_SCORE or 0.5).").option("--max-bytes <n>", "Response size budget in bytes (default: CEREFOX_MAX_RESPONSE_BYTES or 200000).").option("-r, --requestor <name>", "Agent / user name (recorded in usage log).").option("--json", "Emit machine-readable JSON instead of the default text.").option("--only-metadata", "List matching docs (id, score, chunks, chars, partial/full) WITHOUT their content — like the web UI's collapsed result list. Grab a [id:…] then `cerefox document get <id>`.").action(action28);
76668
76689
  }
76669
76690
 
76670
76691
  // src/cli/commands/self-update.ts
@@ -80300,7 +80321,7 @@ async function runSearch(ctx, opts) {
80300
80321
  p_match_count: Math.min(count, 5),
80301
80322
  p_alpha: 0.7,
80302
80323
  p_project_id: projectId,
80303
- p_min_score: 0
80324
+ p_min_score: getMinSearchScore()
80304
80325
  };
80305
80326
  if (metadataFilter)
80306
80327
  params.p_metadata_filter = metadataFilter;
@@ -81983,9 +82004,9 @@ function registerRenameHusks(program2) {
81983
82004
  }
81984
82005
  }
81985
82006
  function buildProgram() {
81986
- const progName = process.env.CEREFOX_PROG_NAME || "cerefox";
81987
- const program2 = new Command(progName).description("Cerefox — user-owned shared memory for AI agents.").version(PKG_VERSION, "-v, --version", `Print the ${progName} version and exit.`).addOption(new Option("--json", "Emit machine-readable JSON on stdout instead of the default human text. " + "Available on read commands; ignored on commands without a JSON shape.").hideHelp()).showHelpAfterError(`(run \`${progName} --help\` for usage)`).enablePositionalOptions().addHelpText("after", `
81988
- Resource groups (run \`${progName} <group> --help\`):
82007
+ const progName2 = process.env.CEREFOX_PROG_NAME || "cerefox";
82008
+ const program2 = new Command(progName2).description("Cerefox — user-owned shared memory for AI agents.").version(PKG_VERSION, "-v, --version", `Print the ${progName2} version and exit.`).addOption(new Option("--json", "Emit machine-readable JSON on stdout instead of the default human text. " + "Available on read commands; ignored on commands without a JSON shape.").hideHelp()).showHelpAfterError(`(run \`${progName2} --help\` for usage)`).enablePositionalOptions().addHelpText("after", `
82009
+ Resource groups (run \`${progName2} <group> --help\`):
81989
82010
  ` + ` document get · list · edit · delete · restore · ingest · ingest-dir · version {list·archive·unarchive}
81990
82011
  ` + ` project list · create · edit · delete
81991
82012
  ` + ` metadata keys · search
@@ -82008,8 +82029,8 @@ Exit codes:
82008
82029
  ` + ` 1 user error 3 not found (document / version / project)
82009
82030
  ` + `
82010
82031
  Learn more:
82011
- ` + ` ${progName} guides list # bundled docs (offline)
82012
- ` + ` ${progName} doctor # diagnose your install
82032
+ ` + ` ${progName2} guides list # bundled docs (offline)
82033
+ ` + ` ${progName2} doctor # diagnose your install
82013
82034
  ` + ` https://github.com/fstamatelopoulos/cerefox
82014
82035
  `);
82015
82036
  registerSearch(program2);
@@ -147,6 +147,32 @@ operations.
147
147
 
148
148
  ---
149
149
 
150
+ ## Local / self-hosted (World B) — a different access model
151
+
152
+ Everything above describes the **cloud / Supabase** deployment. The **local / self-hosted**
153
+ backend ([`setup-local.md`](setup-local.md)) runs Postgres + PostgREST + the Cerefox server
154
+ in one Docker container, and its access model is deliberately simpler:
155
+
156
+ - **No Layer 1 (Edge Functions) and no anon-JWT.** There are no Edge Functions; the
157
+ `cerefox-server` inside the container exposes `/rest/v1` (a reverse-proxy to the in-container
158
+ PostgREST) plus `/app` + `/api/v1`. Remote agents over HTTP are not a goal of World B.
159
+ - **The access token never leaves the container.** db-init self-generates the PostgREST JWT
160
+ secret on boot and mints a `service_role` token into the container's runtime env. The web
161
+ UI (served by the container) and the in-container CLI/MCP read it internally — nothing on
162
+ the host holds it.
163
+ - **Agents use stdio over `docker exec`, not a network credential.** `cerefox-local mcp`
164
+ runs `cerefox mcp` inside the container via `docker exec -i`; the MCP client launches that
165
+ as a local subprocess. No URL, no bearer token in the client config.
166
+ - **The only host-side secret is `OPENAI_API_KEY`** (in `~/.cerefox/local/.env`), used for
167
+ embeddings — the same as every deployment.
168
+ - By default the container publishes on **`127.0.0.1`** (loopback only); set
169
+ `CEREFOX_LOCAL_BIND=0.0.0.0` to expose it on the LAN.
170
+
171
+ So Layers 1–3 below apply to the cloud deployment; the local backend collapses them into a
172
+ single container with an internally-held token.
173
+
174
+ ---
175
+
150
176
  ## Summary
151
177
 
152
178
  | Caller | Transport | Auth credential | Typical use |
@@ -23,6 +23,8 @@ Within a single runtime (e.g., Claude Code's agent teams feature, or a LangGraph
23
23
 
24
24
  Cerefox sits in a unique position: it is vendor-neutral, protocol-native (MCP + REST), and designed for persistent storage. Any agent that can make an HTTP call can read and write to Cerefox.
25
25
 
26
+ > **Cross-machine coordination assumes the cloud / Supabase backend** (a shared network endpoint). The default **local / self-hosted (Docker) backend is single-machine** — it binds `127.0.0.1` and agents reach it via `cerefox-local mcp` (stdio). To coordinate agents across machines with a local backend, expose it on your LAN (`CEREFOX_LOCAL_BIND=0.0.0.0`) or use the cloud backend.
27
+
26
28
  The coordination model is **asynchronous and knowledge-based**:
27
29
 
28
30
  1. **Agent A writes** a finding, decision, or task breakdown to Cerefox. It does not need to know which agent will consume it.
@@ -4,12 +4,18 @@ Comprehensive reference for every `cerefox` subcommand. For tutorials and walkth
4
4
 
5
5
  > `--help` is canonical. If anything in this document disagrees with `cerefox <subcommand> --help`, trust `--help` and file an issue against this guide.
6
6
 
7
+ > **Local / self-hosted (Docker) backend?** Every KB verb below is identical, but you run it
8
+ > as **`cerefox-local <verb>`** (it proxies into the container via `docker exec`); lifecycle
9
+ > is different (`cerefox-local init/start/stop/upgrade/uninstall/status/logs/configure-agent`).
10
+ > A local user sets **only `OPENAI_API_KEY`** — the Supabase/database vars below do **not**
11
+ > apply (the container owns them). See [`setup-local.md`](setup-local.md).
12
+
7
13
  ## Setup
8
14
 
9
- Every command reads configuration from `.env` in the working directory (or environment variables — see [`configuration.md`](configuration.md)). Required at minimum:
15
+ This section is for the **cloud / Supabase** backend. Every command reads configuration from `.env` in the working directory (or environment variables — see [`configuration.md`](configuration.md)). Required at minimum:
10
16
 
11
17
  - `CEREFOX_SUPABASE_URL` and `CEREFOX_SUPABASE_KEY` for any command that talks to Supabase
12
- - `OPENAI_API_KEY` (or `CEREFOX_FIREWORKS_API_KEY`) for any command that embeds (ingest, search)
18
+ - `OPENAI_API_KEY` for any command that embeds (ingest, search)
13
19
  - `CEREFOX_DATABASE_URL` for `cerefox server deploy` and the contributor scripts (`bun scripts/db_*.ts`)
14
20
 
15
21
  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)).
@@ -86,7 +92,7 @@ Walks `DIRECTORY` **recursively** (always — there is no recurse toggle) and in
86
92
 
87
93
  | Flag | Type | Default | Description |
88
94
  |---|---|---|---|
89
- | `--extensions <list>` (`-e`) | comma list | `.md,.txt` | File extensions to ingest, e.g. `--extensions .md`. |
95
+ | `--extensions <list>` (`-e`) | comma list | `.md,.txt` | File extensions to ingest, e.g. `--extensions .md`. `.docx` is **not** in the default set — opt in with `--extensions .md,.txt,.docx` (converted via mammoth, same as single-file ingest). |
90
96
  | `--project-name <name>` (`-p`) | str | _none_ | Project to assign every document to. |
91
97
  | `--update-if-exists` (`-u`) | flag | off | Update existing documents by source path / title. |
92
98
  | `--metadata <json>` (`-m`) | JSON | `{}` | JSON metadata applied to every file in the run. |
@@ -250,16 +250,9 @@ OPENAI_API_KEY=sk-...
250
250
  # All other settings use defaults
251
251
  ```
252
252
 
253
- ## Example: Fireworks Embedder `.env`
254
-
255
- ```bash
256
- CEREFOX_SUPABASE_URL=https://abcdefghijkl.supabase.co
257
- CEREFOX_SUPABASE_KEY=eyJhbGciOiJIUzI1NiIs...
258
- CEREFOX_DATABASE_URL=postgresql://...
259
-
260
- CEREFOX_EMBEDDER=fireworks
261
- CEREFOX_FIREWORKS_API_KEY=fw_...
262
- ```
253
+ > **Fireworks is not wired in the TS runtime yet** — `CEREFOX_EMBEDDER=fireworks` /
254
+ > `CEREFOX_FIREWORKS_*` are documented for the retired Python runtime but are currently
255
+ > no-ops (OpenAI is the only embedder implemented today). Tracked for a future release.
263
256
 
264
257
  ---
265
258
 
@@ -59,6 +59,20 @@ Three top-level paths plus a few special cases:
59
59
  > available in [`examples/mcp-configs/`](../examples/mcp-configs/). Pick the one for your
60
60
  > client, replace the placeholders, and you're connected.
61
61
 
62
+ ### Local / self-hosted (World B)
63
+
64
+ If you run the **Docker backend** ([`setup-local.md`](setup-local.md)) instead of cloud, the
65
+ MCP path is different: the server runs **inside the container**, launched per session over
66
+ `docker exec`. There's no URL or bearer token in the client config — the access token stays
67
+ in the container.
68
+
69
+ - **Easiest:** `cerefox-local configure-agent` wires it up (registers an MCP server named
70
+ `cerefox-local` with Claude Code if the `claude` CLI is present, else prints the snippet).
71
+ - **Manual:** point the client at `command: cerefox-local, args: ["mcp"]` (stdio). That proxies
72
+ to `cerefox mcp` in the container; the same 10 tools, identical behavior to every other path.
73
+ - The cloud paths above (remote Edge Function, GPT Actions) **do not apply** to a local-only
74
+ install — there are no Edge Functions.
75
+
62
76
  ---
63
77
 
64
78
  ## Prerequisites
@@ -116,12 +116,34 @@ These limits comfortably cover personal-use traffic. Check
116
116
 
117
117
  ---
118
118
 
119
+ ## Scenario C — Fully local / self-hosted (Docker)
120
+
121
+ The whole backend runs in one Docker container on your machine — Postgres + pgvector +
122
+ the Cerefox server — with **no Supabase and no Edge Functions** ([`setup-local.md`](setup-local.md)).
123
+
124
+ ```
125
+ Your machine
126
+ └── Docker container (free)
127
+ └── Postgres + pgvector + cerefox web/MCP
128
+ Embeddings via OpenAI API (pay-per-use)
129
+ ```
130
+
131
+ **Typical cost for personal use**: just the **OpenAI embedding spend** (the same pay-per-use
132
+ as every scenario — fractions of a cent per document) plus local compute/electricity. There
133
+ is **no Supabase tier and no Edge-Function invocation limit** to worry about — the binding
134
+ free-tier constraint from Scenarios A/B (500K EF calls/month) simply doesn't exist here, and
135
+ agents using the local MCP server make zero billable cloud calls. The only ongoing cost is
136
+ embeddings (and only when you ingest or run semantic/hybrid search) — see "Controlling
137
+ embedding costs" below.
138
+
139
+ ---
140
+
119
141
  ## Controlling embedding costs
120
142
 
121
143
  If you want to keep costs as low as possible:
122
144
 
123
- - **Fireworks AI** is an OpenAI-compatible alternative that offers competitive embedding prices.
124
- See `docs/guides/configuration.md` for how to switch.
145
+ - **Cheaper embedding models**: a lower-cost OpenAI-compatible provider (e.g. Fireworks AI)
146
+ is on the roadmap — **not yet wired in the TS runtime** (OpenAI only today).
125
147
  - **Batch ingest, don't re-ingest**: Cerefox deduplicates by content hash — re-ingesting the
126
148
  same file twice costs nothing. Only new or changed content triggers embedding calls.
127
149
  - **`cerefox server reindex`**: Re-embeds all existing chunks if you switch embedders. Run this once
@@ -36,11 +36,13 @@ That's it. No Node, Bun, Postgres, or repo clone needed.
36
36
  ## Step 1 — Install
37
37
 
38
38
  ```bash
39
- OPENAI_API_KEY=sk-... sh -c "$(curl -fsSL https://github.com/fstamatelopoulos/cerefox/releases/latest/download/install-local.sh)"
39
+ curl -fsSL https://github.com/fstamatelopoulos/cerefox/releases/latest/download/install-local.sh | sh
40
40
  ```
41
41
 
42
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
43
+ installs a `cerefox-local` command (symlinked into `~/.local/bin`). To set your OpenAI key
44
+ inline at install instead of via `cerefox-local init` (Step 2), use the command-substitution
45
+ form: `OPENAI_API_KEY=sk-... sh -c "$(curl -fsSL …/install-local.sh)"`. Pick a specific port
44
46
  with `PORT=8017 …`.
45
47
 
46
48
  > If the installer warns that `~/.local/bin` isn't on your `PATH`, add it:
@@ -48,7 +50,12 @@ with `PORT=8017 …`.
48
50
  > echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
49
51
  > ```
50
52
 
51
- The web UI is now at **http://localhost:8000/app/** (or your chosen port).
53
+ The web UI is now at **http://localhost:8000/app/** — **or the port the installer chose**
54
+ (it auto-steps to 8010/8020/… if 8000 is busy or you also run the cloud `cerefox web`, which
55
+ defaults to 8000). The installer prints the actual URL; `cerefox-local status` shows it too.
56
+
57
+ The installer also wires **shell tab-completion** for `cerefox-local` (best-effort) — run
58
+ `exec $SHELL` or open a new terminal to activate it.
52
59
 
53
60
  **How the credential works:** the container generates its own JWT secret on first boot and
54
61
  mints the access token internally — the token never leaves the container. The only secret
@@ -10,6 +10,7 @@ to re-run.
10
10
  |---|---|
11
11
  | **Installer / npm** (end user, no repo clone) | `cerefox self-update` (or re-run the [installer](quickstart.md#1-install), or `bun/npm update -g @cerefox/memory`). Then `cerefox server deploy` **if the release notes flag a server-side change**. `cerefox doctor` verifies. |
12
12
  | **Source checkout** (`git clone`, contributor) | `git pull`, then `cerefox server deploy` (or the lower-level `bun scripts/db_*.ts` + `npx supabase functions deploy`). Rebuild the SPA if you run `cerefox web` from source. |
13
+ | **Local / self-hosted (Docker, World B)** | `cerefox-local upgrade` — pulls the new image and recreates the container (data persists in the volume; OpenAI key + tuning overrides preserved). **No separate `server deploy`/`reindex`**: the CLI, web, PostgREST, and schema all ship together in one versioned image, so they can't drift. See [`setup-local.md`](setup-local.md). |
13
14
 
14
15
  > **On an old pre-installer clone (0.1.x)?** The cleanest upgrade is to stop
15
16
  > running from the repo and install the package: follow the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerefox/memory",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
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",