Releases: fstamatelopoulos/cerefox
v0.11.1
Fixed
- Content updates no longer wipe a document's metadata. Every transport defaulted
an absentmetadataargument to{}and the ingest RPC applied it verbatim — so any
content update that didn't re-pass the tags (CLIdocument ingestwithout
--metadata, MCPcerefox_ingest, the REST EF, the frozen Python fallback) silently
cleared the document's metadata. And since metadata is not versioned, the loss was
unrecoverable. The contract is now NULL = "not provided" → keep existing (create
uses{}), enforced once in thecerefox_ingest_documentRPC; pass{}explicitly
to deliberately clear. Schema version 0.5.0 → 0.6.0 (RPC-only; run
cerefox server deploy— v0.11.1 clients sending NULL against a 0.5.0 server would
fail the NOT NULL constraint on update). - CLI parity:
cerefox metadata searchno longer requires--metadata-filter.
Like the MCP tool / EF (relaxed in v0.10.x — the CLI was missed), at least one of
filter /--project-name/--updated-since/--created-sinceis required;
--project-namealone lists that project's documents.
v0.11.0
Changed — BREAKING
- Optimistic concurrency control on content updates (design:
docs/specs/concurrency-control-design.md).
Updating a document's content (viadocument_idorupdate_if_exists) now requires
expected_content_hash— thecontent_hashof the version the edit was based on,
returned by every read surface (cerefox_get_document,cerefox_search,
cerefox_metadata_search, the REST EFs,cerefox document get/cerefox search,
and the web edit page). The check is atomic inside thecerefox_ingest_documentRPC
(SELECT … FOR UPDATE), closing the read→embed→write race where two concurrent
writers silently last-write-wins'd each other. A stale hash fails with a conflict
(re-read → merge → retry; HTTP 409 on the REST path); a missing hash fails with
token-required (HTTP 400).last_write_wins: true(CLI--last-write-wins)
explicitly skips the check and is recorded in the audit log —document ingest-dir
andguides ingestpass it internally (the filesystem / npm package is their source
of truth), and the frozen Python fallback declares it to preserve its historical
behavior. Breaking: pre-v0.11 clients' content updates fail against an upgraded
server until updated (cerefox self-update); existing GPT Actions need the v2.0.0
OpenAPI block re-pasted. Creates are unaffected. Schema version 0.4.0 → 0.5.0
(RPC-only change; ships viacerefox server deploy --schema-only).
Added
content_hashreturned by all document-shaped reads (MCP tool headers, CLI output,
REST EF responses, web document API) — the token for the concurrency contract above.- CLI flags
--expected-content-hash/--last-write-winsoncerefox document ingest. - Web edit page detects mid-edit concurrent changes and shows a merge-needed conflict
error instead of silently overwriting.
Fixed
- Web edit page could corrupt metadata keys via the key autocomplete. The key
suggestions embedded the usage count in the option label (status (108)), and
Mantine's Autocomplete inserts the label into the field on select — so picking a
suggestion (and saving) stored the literal stringstatus (108)as the metadata key,
polluting the KB taxonomy (it then showed up in the key list asstatus (108) (1)).
The dropdown now shows the count viarenderOption("status · 108 docs" style),
while only the bare key ever enters the field. The search filter's key Select (which
was never affected — Select keeps value/label separate) now labels the count as
"(N docs)" for clarity.
v0.10.4
Added
cerefox_metadata_searchcan now list a project's documents — closing a CLI↔MCP
parity gap (the CLI'scerefox document list --project <name>had no MCP equivalent).
metadata_filteris now optional: supplyproject_name(and/orupdated_since/
created_since) alone to list documents by scope, ordered newest-updated first. At
least one ofmetadata_filter/project_name/updated_since/created_sinceis
still required, so the tool never becomes an unbounded whole-KB dump. Backward
compatible — existing non-empty-filter callers are unaffected. The twin
cerefox-metadata-searchEdge Function and the GPT Actions OpenAPI block
(info.version→ 1.9.0) were relaxed in lockstep. A new CLI ↔ MCP parity matrix in
docs/guides/cli.mddocuments the full surface and the remaining
(intentional vs. actionable) gaps.cerefox document set-projects <document-id> [names…]— new CLI command
closing the reverse parity gap (thecerefox_set_document_projectsMCP tool
had no CLI form). Full-set replace of a document's project memberships
(--clearremoves all); created-if-missing, case-insensitively de-duplicated,
logged as anupdate-metadataaudit entry. Shares the membership-replace core
with the MCP tool (_shared/mcp-tools/_projects.ts → replaceDocumentProjects)
so both behave identically.
v0.10.3
Fixed
cerefox server deployEdge Functions now deploy via the Supabase Management API
(--use-api) instead of the local Docker bundler. The Docker bundler bind-mounts the
function source dir, which fails (entrypoint path does not exist) when the npm package
is installed under a path Docker Desktop won't file-share — notably/usr/local(the
classic Homebrew/npm config set prefix /usr/locallocation) — and Docker Desktop is
running. The API path is Docker-independent, so the deploy works regardless of where npm
placed the package or whether Docker is up. (Thanks @tdebasis — #84.)
v0.10.2
Fixed
- Web search now actually applies
CEREFOX_MIN_SEARCH_SCORE. The v0.10.1 fix was
incomplete: the web UI defaults todocsmode, but only thehybridbranch in
discovery.tswas updated — thedocsbranch still passedp_min_score: 0.0(a
replace_allmissed it due to a different indent). The default web search therefore
applied no threshold. Both branches now usegetMinSearchScore(). (Note: in hybrid/docs,
the threshold filters vector-only matches; FTS keyword matches still pass by design.) - CLI honors
CEREFOX_MAX_RESPONSE_BYTES. The CLI enforces a response byte budget
(--max-bytes) but ignored the env var; its default now reads
CEREFOX_MAX_RESPONSE_BYTES(200000 fallback). Corrected CLAUDE.md: the budget applies
to MCP/EF and the CLI; only the web UI is unlimited.
Security
- Local container binds to
127.0.0.1by default (was0.0.0.0), so a single-user
self-hosted backend isn't exposed on the LAN. Opt in withCEREFOX_LOCAL_BIND=0.0.0.0.
Docs
- World-B (local/self-hosted) coverage across the guides:
upgrading.md
(cerefox-local upgrade),operational-cost.md(fully-local scenario — no Supabase/EF
cost),access-paths.md(in-container PostgREST + docker-exec MCP; token never leaves
the container),connect-agents.md(cerefox-local configure-agent/cerefox-local mcp).
Added — local backend (World B), continued
cerefox-local configure-agent --tool <client>now wires non-Claude clients too
(Claude Desktop, Cursor, Codex, Gemini), not just Claude Code. It reuses the bundled
config writers via a one-shotdocker run(the bin gains a--localflag that points
the MCP entry at thecerefox-local mcpshim); Claude Code still goes through
claude mcp addon the host.- Shell completion is program-name aware + auto-installed.
cerefox completion <shell>
emits a script bound to the actual program name, socerefox-local completion <shell>
produces a workingcerefox-localcompletion that doesn't clash with the cloudcerefox
one (functions + bindings namespaced; cloud output unchanged).install-local.shnow
wires it up host-side (best-effort, idempotent) — generating the script from the
container and sourcing it from your shell rc, mirroring the cloud installer + printing an
"exec $shell" hint. (Thecompletion installsubcommand itself can't be used for World B
— proxied into the container, it would write inside it — hence the host-side wiring.)
v0.10.1
Fixed — .env overrides dropped in the Python→TS migration
Several documented CEREFOX_* options were silently no-ops in the TS runtime. Each now
has a single default honored consistently by the CLI, MCP, and web — and forwarded into
the local/World-B container:
CEREFOX_MIN_SEARCH_SCORE(default0.5). The web API previously passed0.0, so
the web UI surfaced irrelevant low-similarity results; it now matches CLI/MCP.CEREFOX_MAX_RESPONSE_BYTES(MCP/Edge-Function ceiling; web + CLI stay unlimited).CEREFOX_MAX_CHUNK_CHARS/CEREFOX_MIN_CHUNK_CHARS/CEREFOX_VERSION_RETENTION_HOURS
/CEREFOX_VERSION_CLEANUP_ENABLED(ingestion).CEREFOX_BACKUP_DIR(cerefox backupdefault).- OpenAI embedding overrides
CEREFOX_OPENAI_BASE_URL/_EMBEDDING_MODEL/
_EMBEDDING_DIMENSIONS. ⚠ changing model/dimensions is breaking — requires
cerefox server reindex(DB column isvector(768)); documented loudly. - A
bun testguard now fails if any.env.examplevar isn't referenced in the TS source
(cheap regression guard against future migration drift)..env.examplecleaned up:
removed the no-opCEREFOX_LOG_LEVEL; marked Fireworks as not-yet-implemented in TS.
Changed — local backend (World B) polish
install-local.shauto-selects a free host port (steps+10past a busy port, and
past8000when a cloud install shares that default) instead of silently colliding.- Detect-and-guide when Docker is missing or its daemon is stopped (no auto-install).
- World-B users can put the
CEREFOX_*tuning overrides above in~/.cerefox/local/.env;
they're forwarded into the container (apply withcerefox-local init).
Docs
- README presents cloud vs local as two backend options; trimmed "Project status".
- Fixed stale items:
.docxingest is supported (mammoth; only PDF dropped); CLI old
flat verbs are husks (not "removed");--mode hybrid(notsemantic); quickstart
timing +setup-local.mdmis-links; "Python CLI/web" framing.
v0.10.0
Local / self-hosted Cerefox backend (new deployment mode — "World B"). Run Cerefox
entirely on your own machine — Postgres + pgvector + PostgREST + cerefox-server in one
Docker container — with no cloud dependency and no Node/Bun on the host. It reuses
the existing schema, RPCs, MCP handlers, web app, and supabase-js data client unchanged
(config-only); cloud (Supabase) deployments are completely unaffected. Cloud and local
are independent worlds — separate installers, separate command names (cerefox vs
cerefox-local).
Added
- All-in-one Docker image (
docker/local/Dockerfile): pgvector + pinned PostgREST +
the bundled app + thecerefox-localhost script, supervised by s6-overlay
(db-init → postgres/postgrest/cerefox-server). The container self-generates its JWT
secret on boot and mints the access token internally — the token never leaves the
container. Published multi-arch (amd64+arm64) to ghcr.io/.../cerefox-local by
.github/workflows/local-image.yml— opt-in viacut_release.ts --docker-publish
(decoupled from cutting a Release, same policy as the npm publish). - One-line local installer (
docker/local/install-local.sh, shipped as a Release
asset):curl -fsSL …/install-local.sh | sh. Docker-only — pulls the image, runs it
with--restart unless-stopped, waits for readiness, and installs acerefox-local
command on PATH. The only host-side secret isOPENAI_API_KEY(in
~/.cerefox/local/.env); the cloud~/.cerefox/.envis never touched. cerefox-localcommand: host-side lifecycle (init,start/stop/restart,
upgrade,uninstall [--purge],status,logs,configure-agent) plus a proxy that
runs every KB verb (search,document,project,mcp, …) inside the container via
docker exec— so MCP stdio works and the same bundled binary serves the local backend.
cerefox-local initsets/rotates the OpenAI key after install.CEREFOX_PROG_NAME: the bundled bin presents ascerefox-localin help/usage when
the shim sets it (one binary, no fork)./rest/v1reverse-proxy in cerefox-server (registerPostgrestProxy), mounted only
whenCEREFOX_POSTGREST_UPSTREAMis set — so it is inert in cloud. Makes the server
the single local gateway (UI +/api/v1+/rest/v1).cut_release.tsnow uploadsinstall-local.shas a Release asset (next to
install.sh).- Version-coupling CI (
.github/workflows/version-coupling.yml): runs the read/write
smoke against the pinned PostgREST so asupabase-jsbump that breaks the local stack
fails CI.
Fixed
- Local image Help page: bundle the docs + agent guides into the image so
/app/help
renders offline (was "No bundled docs available").
Design: docs/research/local-cerefox-design.md; plan: docs/plan.md (Iteration 30).
Polish deferred to v0.10.1: cerefox-local --help merge, in-bin configure-agent --local for non-Claude clients, and cerefox-local shell completion.
v0.9.11
Fixed
- Web UI analytics now records usage. The
/api/v1web routes never called the
usage-logging RPC, so the Analytics page stayed empty even with usage tracking
enabled (only the CLI and MCP tools logged). The web layer now logssearch,
get-document, andingestoperations (access_path = "webapp", fire-and-forget,
best-effort — never blocks the response). Thecerefox_log_usageRPC, config gate,
and report query were all already correct; this closes the missing call sites.
v0.9.10
Installer/upgrade reliability. Client-only — no server deploy.
Fixed
- Stale-manifest-cache upgrades —
install.shandcerefox self-update
now bypass the package manager's cached registry manifest (--no-cachefor
bun,--prefer-onlinefor npm) when installing/upgrading. Previously, if a
new version was published soon after a prior install, bun could reuse a
still-"fresh" cached manifest that didn't list the new version — so a
re-install resolved@latestto the old version (and even an explicit
@<new>failed with "No version matching"). Forcing a fresh manifest fetch
makes upgrades deterministic regardless of release cadence.
v0.9.9
Document version UX + docs/completion polish. Client-only — no server deploy.
Added
- View an archived version in place — clicking a version number (or "Open
this version" in its ⋯ menu) opens that snapshot read-only at
/document/:id?version=<id>, with a "Previous version: vN" banner and a
"View current version" link back. In version view the header offers only
Download and a Protect / Unprotect toggle (the version's
archive/cleanup-protection flag); Edit, Delete, the review pill, and the
Chunks tab are hidden. - Per-version size in the Versions card — each row now shows
N chunks · M chars, and the actively-viewed version is highlighted.
Changed
cerefox completion install(zsh) now self-bootstrapscompinitif no
completion system has been initialized yet, so cerefox completion registers
even on a bare shell. It's a no-op whencompinitalready ran (no double
init).- Quickstart title no longer claims "5 Minutes"; adds a dedicated Step 0:
Create a Supabase project (linkingsetup-supabase.md) so the prerequisite
is explicit rather than buried.