[embedding] and [rerank] configuration become optional at runtime — EverOS now boots with only [llm] configured and degrades into three capability tiers, with a new everos cascade backfill command to fill in rows written without an embedding provider.
This release also hardens the cascade queue's retry and delete handling, and fixes a path traversal in knowledge upload — see Security for the affected versions.
Added
[embedding]and[rerank]are now soft runtime dependencies — EverOS boots and serves requests with only[llm]configured. A missing or misconfigured embedding / rerank / multimodal provider no longer aborts startup; the accessor logs<provider>_capability_build_failedand reportsavailable=False. Features degrade into three tiers: Tier 1 ([llm]only) → KEYWORD search + add/flush + md writes + cascade sync; Tier 2 (+ [embedding]) → adds VECTOR/HYBRID search + reflection + skill extraction + backfill; Tier 3 (+ [rerank]) → adds AGENTIC search + knowledge write/search. Tier upgrades require a server restart. Downgrades are read-safe: knowledge documents stay readable / renamable / deletable after a Tier-3 → Tier-2 downgrade; only write and search endpoints return 422.everos cascade backfillCLI command — three-phase interactive backfill (vectors→clusters→skills, or--phase all) that upgrades Tier-1 rows to Tier-2 once[embedding]is configured. Each phase prints row / token estimates and blocks ony/N;--yes/-yfor CI. Exit codes:0success,1user declined,2phase preconditions unmet,3server running,4completed-with-failures,130SIGINT.- LanceDB schema v2 — the six business tables (
episode,atomic_fact,foresight,agent_case,agent_skill,knowledge_topic) now allowvector NULL, so cascade can write rows without vectors when[embedding]is unavailable and a later backfill fills them in. The migration runs once on first startup under a cross-processmemory_root_lock(fcntl.flock), followed by a per-tableoptimize(cleanup_older_than=timedelta(0))to physically prune older manifest versions. - Startup unbackfilled-rows banner — after the LanceDB lifespan, a sweep emits
unbackfilled_memory_rowswhen rows withvector IS NULLexist, pointing ateveros cascade backfill. - PyPI Trusted Publishing workflow — tag-triggered
.github/workflows/release.ymlbuilds, smoke-tests and uploads via OIDC (no stored token) behind thereleaseenvironment's manual-approval gate. A version / tag mismatch aborts the publish. Companion/releaseskill lives under.claude/skills/release/.
Changed
ProviderNotConfiguredError→ HTTP 422CAPABILITY_UNAVAILABLE— write / search endpoints that need embed or rerank now return 422 with a section-aware hint (pointing at theeveros.tomlsection, never atEVEROS_*env vars) instead of erroring at startup or 500-ing at request time.GET /healthreturns a PydanticHealthResponsemodel — with typedcapabilitiesanddisabled_featuresfields, so OpenAPI codegen produces real shapes instead ofadditionalProperties: true.MemoryRoot.default()→MemoryRoot.resolve()— renamed to make the precedence walk (--root/EVEROS_ROOT/ default) explicit. Adefault()alias is kept as a backward-compatibility shim that forwards toresolve()and emits aDeprecationWarning; it will be removed in a future major release, so update call sites when convenient.- Uncalibrated recall scores moved to their own name —
KEYWORDand single-routeVECTORsearches now report their top score asrecall_top_score_raw;recall_top_scoreis reserved for the calibrated methods (HYBRIDLR sigmoid,AGENTICcross-encoder), whose values share a comparable[0, 1]scale. Langfuse aggregates scores by name, so the previous single name meant a chart could average an unbounded BM25 score together with a probability. Every recall score also carriesmetadata = {"method": ..., "calibrated": ...}. Dashboards built onrecall_top_scorefor keyword search need to switch to the new name. - Docs and examples now use
/api/v2— README, QUICKSTART, thedocs/reference set, the Langfuse example andeveros demo --liveall call the canonical/api/v2prefix./api/v1keeps resolving to the same handlers, so nothing breaks, but it is now described as a legacy compatibility alias that may be removed in a future major release rather than a permanent one. New integrations should target/api/v2. cluster_repo.find_cluster_id_for_membernow requires(app_id, project_id, owner_id)— reverse-index lookups JOINClusterfor scope filtering.entry_idis per-owner unique by design, so the reverse index alone could collide across owners writing on the same day.- All six cascade handlers register unconditionally — a Tier-3 → Tier-2/1 downgrade no longer strands DELETE / PATCH events. Embed-requiring branches inside each handler body-guard on capability availability at execution time.
- Interactive TTY log level defaults to WARNING — keeps INFO lines from drowning out the backfill
y/Nprompts; non-interactive / CI stays at INFO, and--verbose/-vforces INFO. click>=8.1promoted to a first-class dependency — previously transitive via typer.typer.Abortandclick.exceptions.Abortare distinct classes under typer 0.15+, so the interrupt catch incascade backfillcovers both.- Test harness pins
EVEROS_ROOTto a temp path —conftest.pyscrubs everyEVEROS_*env var so a developer's~/.everos/everos.tomlcannot make tests accidentally green against a real provider.
Fixed
- Cascade retry classification and total-retry budget — the worker now catches
ExternalServiceError(transient embedding / LLM / rerank failures) and retries inline up to 3 times before marking a rowretryable=True. A total budget of 12 attempts across scanner cycles bounds retrying during a prolonged outage, andfailedrows withretryable=Falseon a stable mtime skip auto-retry, so editing and re-saving the md is what grants another attempt. - The reconciler no longer overwrites the worker's
mark_done—pending/processingrows with a stable mtime are no longer re-enqueued. SQLiteREALround-trip precision loss in mtime comparisons is absorbed with a 10 ms tolerance. - A file deleted while its
modifiedevent was still queued is now processed as a deletion — previously the handler raisedFileNotFoundError, which left a stale indexed row and a permanently failed queue item behind. - Stuck
optimize()escalates to a full index rebuild — after 5 consecutive failures the worker falls back todrop_index + create_indexinstead of letting compaction and version cleanup stay wedged (workaround for thelance-format/lance#7653panic path). - The embedding provider raises on HTTP 200 with empty
data— it previously returned zero-length vectors silently, corrupting search results. - Episode extraction retries on malformed LLM output — the synchronous
/flushpath retries everalgoValueError(typically a truncated provider response) twice with 1 s / 2 s backoff before surfacing a 500. - Filename validation on knowledge upload — NUL bytes and filenames longer than 255 UTF-8 bytes now fail fast with
InvalidInputError→ HTTP 400 instead of surfacing OS errors as a 500 with a half-written md file. - HTML upload no longer takes the UTF-8 fast path — knowledge upload's plaintext short-circuit uses an explicit allowlist (
text/plain,text/markdown,text/x-rst,text/x-markdown) plus known extensions;text/htmlis deliberately excluded so HTML still goes through everalgo'sclean_html_for_llm. Prevents a 503 when a Tier-3 user without[multimodal]uploads a markdown doc. - Broken table-of-contents links in
docs/api.md— the endpoint anchors still pointed at the pre-1.2.0#post-apiv1…slugs after the headings moved to/api/v2, leaving all five TOC links dead.
Removed
- README "Star us" section.
Security
-
Knowledge upload path traversal (CWE-22) — the knowledge document upload joined the untrusted multipart filename into
_original/verbatim, so an absolute or..-laden filename let a caller write attacker-controlled bytes outside the document directory. The filename is now reduced to a safe basename, and the resolved target is asserted to stay inside_original/before any filesystem touch.Affected: every release before
1.1.4, and1.2.0. Not affected:1.1.4. Fixed in:1.2.1. The fix shipped in1.1.4but was not present on the branch1.2.0was built from, so upgrading1.1.4 → 1.2.0reintroduced it.
Upgrade
pip install --upgrade everos # or: uv sync
On first startup after upgrading, LanceDB runs the schema-v2 migration once — it takes a cross-process lock and optimizes each table afterwards. No manual steps. If rows were written while [embedding] was unavailable, the startup banner will point you at everos cascade backfill to fill in their vectors.
Full changelog: v1.2.0...v1.2.1