Coalent follows semantic versioning. Each release below lists what was Added, Changed, and Removed. Upgrades through 0.3 are backward-compatible — those features are opt-in (see the 0.2 → 0.3 upgrade notes). 0.4 flips two defaults on — extractive understanding and cross-unit recall — each with a one-line escape hatch back to 0.3. 0.5 is strictly additive — every new knob defaults off. 0.6 ships the pool read path opt-in — the default path is unchanged. 0.6.1 is the integrations release — the MCP server and the LangChain package, both additive. 0.7 is the self-healing release — the failure chain, the read's own doubt, and one deliberate default change made loudly: the read path now defaults to pool whenever a semantic embedder is available (explicit read_path="unit" stays byte-identical); every new v0.7 knob is default-OFF and byte-inert until armed.
New in 0.7 — the failure chain. The read ships its own provenance and doubt (Result.sources, max_source_age_s, and — with the observe-only gap detector — probes / probe_coverage / gaps), a planner can hand the read its decomposition and intent (subs=, constraints=), and the cache gains explicit failure verbs your evaluator drives: repair(read_id) (append-only, provenance-stamped, permanent), reprobe(read_id), serve_unserved(read_id). Ingest metadata (meta=) closes the v0.6 attribution gap. And the one deliberate default change: since 0.7.0 the read path defaults to pool whenever a semantic embedder is available — which is every keyed or production deployment; keyless zero-config construction falls back to the unit path with a warning, and passing read_path="unit" explicitly is byte-identical to pre-0.7 behavior. Every new v0.7 knob remains default-OFF and byte-inert (pinned). See The failure chain and Integrating with your failure handling.
In 0.6.1 — the integrations. coalent-mcp puts the cache behind the Model Context Protocol for Claude Code / Claude Desktop / Cursor — bring-your-own vector DB via --cache-factory (measured byte-identical to the library: 0.710 = 0.710 on the same 100 benchmark questions), a zero-config --watch folder mode with its honestly measured cost (0.46 vs 0.71), an HTTP transport where many agents share one compounding cache, and seven tools including the new source_changed freshness signal. Plus langchain-coalent — your unchanged LangChain vector store, embeddings, and chat model as the substrate of a Coalent cache, in one call. The library's read paths are untouched.
In 0.6 — the pool read path ships. read_path="pool" (opt-in) answers every read from the token-budgeted, globally-ranked fresh-claim pool — measured at 0.731 strict accuracy @ 981 mean tokens (n=605): naive k9's accuracy at ~25% fewer tokens, naive's best measured point at ~43% fewer. Plus a default-OFF behavioral stack (residual spans, refusal fallback via report_refusal/report_success, append-only repair, query keys — refusals −33%, +3.1 pts same-store), an adaptive serve gate, a default attribution header with a documented pool_header golden path, reranker and claim_index hooks, and new observability events. The default read path was byte-for-byte v0.5 in this release (the pool default arrived in 0.7.0); the v0.5 serve="pool" preview is deprecated, never auto-mapped, its removal clock running from 0.7.0.
Upgrading to 0.4 — extractive understanding (extract=True) and cross-unit recall (cross_unit_recall=True) are now on by default. A unit's cached understanding is now a query-independent list of atomic claims, not a prose summary, so units re-materialize into the new shape on their next read. To pin exact 0.3 behavior, pass extract=False and cross_unit_recall=False.
Look for the New in v0.7 badges across the docs — they mark features introduced in the latest release (earlier badges mark the release each feature arrived in).
- v0.7.0September 2026Latest
The self-healing release — the read ships its own doubt, the cache gains an explicit failure chain your agent drives, and the read path now defaults to pool wherever a semantic embedder is available (explicit read_path="unit" stays byte-identical to pre-0.7). Every NEW v0.7 knob is default-OFF and byte-inert until armed (pinned).
Changed- THE DEFAULT READ PATH — the one deliberate default change of this release, taking the flip pre-registered in 0.6.0: since 0.7.0 the read path defaults to pool whenever a semantic embedder is available — which is every keyed or production deployment, and the path every published benchmark number was measured on (0.6/0.6.1 were the transition releases where it shipped opt-in). Keyless zero-config construction falls back to the unit path with a warning (pool ranking is measured-unsafe on the keyword-hash fallback embedder). Pass read_path="unit" or "pool" to pin either explicitly; explicit "unit" is byte-identical to pre-0.7 behavior.
- The default pool header is metadata-first: units whose ingests carried Chunk.meta render [title | source | date]; meta-less units keep the 0.6 unit-title fallback, and the construction warning now names the whole ladder. No behavior change for corpora ingested without metadata.
Added- The agentic Result surface — the read carries its own provenance and doubt so an evaluator node can act without drilling: Result.sources (the artifact ids actually behind the served payload, served order first, de-duplicated — both read paths); Result.max_source_age_s (the serve's freshness age: MAX served-owner age in seconds); Result.probes / Result.probe_coverage (the probe texts this read scored and, with the gap detector armed, per-probe {probe, best_claim, best_span, margin, fired}); Result.gaps (the actionable subset {probe, span, unit_id, source, kind} — kind "extraction_hole" = the evidence tier HAS it, repair terrain; "corpus_hole" = nothing reaches the probe, route to YOUR tool); Result.parent_read_id (set on reprobe()/serve_unserved() results).
- gap_detector=True (constructor knob, pool path) — observe-only by construction: per probe, if a raw evidence sentence outscores every fresh claim by a fixed margin, that sentence is banked as a repair candidate on the read's ledger and reported in Result.gaps. Serving is byte-identical ON vs OFF (pinned). $0 at serve: the evidence sentence tier hydrates lazily per unit, embeds once, and is cached.
- get(..., subs=[...]) — planner-owned decomposition: sub-question strings (or {"q", "hyde"} dicts) feed the same probe-union path as the decompose= callable and win over it for that read; subs=[] sanctions no-decomposition; malformed entries fail open to the raw query. The measured composition claim: the full v0.7 chain scored 0.826 adjudicated vs 0.774 for the strongest v0.6 configuration — +5.3 points at an identical ~983-token serving budget; final refusals −69% (61 → 19). Both compositions ship: passing no subs= is the zero-risk mode — first pass byte-identical to v0.6, the chain engages only on failure.
- get(..., constraints={...}) — {"dates": [...], "sources": [...], "entities": [...]} (intent detection's natural output) matched against unit ingest metadata: dates through ONE ISO canonicalizer (never guessed), sources/entities case-insensitive substring. FEEDER ONLY: matched units' best evidence sentences join the read's repair-candidate ledger — constraints never touch pool scoring or serving (pinned). With ≥2 derivable keys the match is AND across keys / OR within a key's values; an empty AND set falls back to OR (constraints_and_fallback event), so the conjunction can narrow but never silence a read's candidates.
- repair(read_id) + repair_extractor= (BYO callable) — the pump. Consumes the read's banked candidates (detector fires + constraints matches, best-first), then bridge candidates derived from the served claims. Per candidate: one span-anchored extractor call ((span_text, context_region, existing_claims) -> [claims] — the library still never calls an LLM itself), mechanical near-dup rejection, then an append-only commit with per-claim provenance (understanding["_repair_provenance"]: claim, span, source, origin, via, ts — a wrong-but-novel claim stays evictable by inspection). Returns a RepairReport (candidates_seen / extracted / rejected / admitted / claims / units_touched). Capped at 8 admissions per call. The store improvement is permanent. Gating repair on a failed read matched always-on accuracy at 14% of the extraction calls.
- Repair admission hygiene — mechanically rejects (before dedup, counted in RepairReport.rejected) the two measured span-extraction defect shapes: antecedent-free pronoun-subject claims and truncated claims (mid-sentence starts, dangling connectors, trailing punctuation cuts).
- reprobe(read_id, hint=None) — the mechanical second pass for buried answers: harvests proper-noun entities from the read's SERVED claims, pairs them with the read's sub-question tails as new probes, one batched embed, then a MAX-union re-rank over the unchanged pool (originals included — nothing served can score worse). Fresh Result with parent_read_id set; embeds only, no LLM, no retrieval, no store mutation. Self-skips (returns None) when there is nothing to harvest.
- serve_unserved(read_id) — the post-repair refusal rung: a fresh Result that force-packs, at the head, (a) the question's admitted-but-unserved repaired claims and (b) the best claims of the strongest constraint-matched unit absent from the served payload, then refills with the original served claims. One embed, no LLM, store never mutated. By app contract, call it only on a refusal — a refusal is never a correct answer, so this rung cannot break one.
- Ingest metadata — Chunk.meta (recognized keys title / source / date, extras preserved), captured onto the unit as source_meta at build, serialized round-trip, and rendered by the metadata-first default pool header ([title | source | date] when present). This closes 0.6.0's documented known-limit: the measured 0.68-vs-0.73 attribution gap was a unit-metadata limit, and units can now carry the metadata. Meta-less ingests keep emitting byte-identical pre-0.7 serde JSON.
- decompose= (constructor callable, default OFF) — first-pass query decomposition for naked deployments: a BYO callable(query) -> [{"q", "hyde"}, ...] whose sub-questions join the probe union (clamped at 4); an explicit subs= always wins. The library never calls an LLM itself.
- New events: gap_detector, constraints_matched, constraints_and_fallback, repair_applied, reprobe, reprobe_skipped, serve_unserved, serve_unserved_skipped, pool_decomposed.
- MCP: get_context now also returns the read's coverage score, the needs_retrieval hint, and gaps (empty unless the factory-built cache armed gap_detector — folder mode never arms it). Folder mode auto-wires ingest metadata for watched files (title = first markdown H1 else filename, source = relative path, date = mtime), so its attribution header upgrades to the measured [title | path | date] rung automatically.
- langchain-coalent: CoalentRetriever document metadata gains needs_retrieval + gaps (additive; gaps empty unless gap_detector is armed on the cache).
Fixed- OpenAIEmbedder.embed_many now chunks requests at the provider's hard 2048-inputs-per-request limit (order preserved, minimum requests). An oversized batch previously 400-failed and could silently degrade a feeder that expected one batched call (pinned: 5000 texts → [2048, 2048, 904]).
Deprecated- With the flip taken, the deprecation clocks pre-registered in 0.6.0 now run from this release: serve="pool" (the v0.5 preview — never auto-mapped to the pool read path) and the pool-inert unit-path read knobs count their notice period from 0.7.0. read_path="unit" itself is NOT deprecated — it is the supported legacy escape hatch and the keyless fallback.
- v0.6.1August 2026
The integrations release — the MCP server and langchain-coalent. Additive; both read paths are untouched.
Added- coalent-mcp — the Coalent MCP server (pip install "coalent[mcp]"; mcp SDK >= 2.0): fresh, attributed facts in any MCP client (Claude Code, Claude Desktop, Cursor). PRIMARY mode is --cache-factory module:function — your factory returns a fully user-constructed SemanticCache (your vector DB, embedder, LLM, every knob); the server adds only the protocol. Measured to transmit library quality with zero loss: 100 frozen benchmark questions over the 609-article corpus scored 0.7100 strict — byte-identical to the library's own 0.7100 on the same questions (identical CIs, 100/100 served, 0 errors, 98/100 payloads byte-equal to the library store). A broken factory fails loud at startup with the module:function named.
- Folder mode (--watch DIR) — the zero-config wedge: the recommended v0.6 deployment (pool path, residual spans, query keys) over a directory; paragraph-chunked built-in retriever, artifact_id = relative path, pool_header auto-wired to "[path | modified date]" (the golden path by default), store at <watch-dir>/.coalent/store.db, fully-warm restarts on an untouched folder. Honest measured cost: 0.46 vs factory mode's 0.71 on the same questions (generic chunking + keyhole lazy builds) — which is why the docs lead with the factory.
- --transport http (streamable HTTP) — one long-lived process, many concurrent agents, ONE shared cache (shared compounding; a single lock serializes tool bodies). Validated: 2 concurrent clients interleaving 20 reads = answers identical to sequential (20/20), one shared cache, zero errors, zero duplicate synthesis. Optional COALENT_MCP_TOKEN requires Authorization: Bearer. stdio remains the default (client-launched, single-writer: don't point two stdio servers at one store — use http to share).
- Seven tools: get_context, report_refusal, report_success, source_changed (new — the BYO freshness signal: your ingestion pipeline invalidates derived facts immediately; hash-skip on unchanged text; in folder mode the scan stays authoritative), list_sources, cache_stats, refresh. Folder freshness is scan-before-serve: you cannot get a stale answer after saving a file — probed at the answer level (mid-run edits flipped served answers on the very next read; zero stale serves observed across the entire validation). One benign regime note: a question about a just-added file can honestly refuse from a warm pool until a build fires for it — nothing stale is ever served.
- SemanticCache.has_source(artifact_id) — True when any cached unit's provenance depends on the artifact: the cheap pre-check for change-feed adapters, so they don't fire source_changed (and trip the wiring warning) for files no unit has ever read.
- langchain-coalent 0.1.0 (its own package: pip install langchain-coalent; deps coalent>=0.6 + langchain-core>=0.3 only) — BYO-first LangChain integration: create_coalent_cache(vectorstore, llm=, embeddings=) builds a cache over your unchanged LangChain stack in one call (every Coalent knob passes through — new library knobs work the day they ship); CoalentRetriever(cache=) is a drop-in BaseRetriever serving the attributed payload with read_id/sources/cache_hit metadata; CoalentVectorStoreRetriever wraps any VectorStore/BaseRetriever as Coalent's substrate; plus a runnable, offline refusal-loop example in the LangGraph node-and-conditional-edge shape.
- v0.6.0July 2026
The pool read path ships — opt-in, with a default-OFF behavioral stack. The default path is unchanged.
Added- read_path="pool" — the claim-pool-first read path (opt-in). Every read is answered by budget-packing the global fresh-claim pool; units remain the ownership / freshness / build / provenance skeleton. Validated at n=605 (strict grading, frozen held-out queries): 0.731 accuracy @ 981 mean context tokens — naive k9's accuracy (0.711 @ 1,311) at ~25% fewer tokens, naive's best measured point (k12 0.731 @ 1,729) at ~43% fewer; gold-claim rank p50/p75/p90 = 1/6/15 in pool order over claim-present queries; zero regressions on the default legs. The shipping default constructor passed the full replay gate with no knob tuning; it still ships opt-in per the deprecation timeline.
- Adaptive serve gate (serve_gate=None) — an explicit float is absolute (adaptation disabled — the reproducible-bench off-ramp); None adapts against the pool's own null-shaped noise ceiling. Shipped only after the replay gate passed: 605/605 serve decisions on both arms, zero builds, zero LLM spend.
- Default pool header — pool_header=None no longer serves an unattributed payload: the built-in default renders "## {unit.query[:60]}" per source group, falling back to "[source: {artifact_id}]". The measured three-point ladder (n=605, strict): opaque id 0.641 (153 refusals) → query-title default 0.678 (136; this ships) → caller metadata callable "[title | source | date]" 0.731 (101; the documented best recipe). The remaining gap is a unit-metadata limit, not header format.
- Behavioral stack (all default-OFF): residual_spans=True — a build-time sentence audit retains fact-bearing source sentences the extractor missed as tier-2 spans on the unit (never in the pool); refusal fallback — every read gets a deterministic Result.read_id (64-read ring buffer); when YOUR answerer refuses, report_refusal(read_id) returns an attributed retry payload from the unit's residual spans (report_success confirms). On the n=605 benchmark: a payload delivered on 91/91 first-pass refusals, net refusals 91 → 61 (−33%), zero newly-wrong answers; the full stack measured +3.1 pts at +2.1% tokens on the same store. Append-only repair: lossy-marked units repair on their next rebuild touch by appending missing facts — claims are never dropped while the source hash is unchanged. query_keys=True (requires the pool path — a loud ValueError otherwise): confirmed rescues attach durable alternate keys, counted only at/above key_floor=0.85; keyed-class first-pass 0% → 61% on mild paraphrases (n=18, small).
- reranker hook — serving order only; serve/build/floor decisions always read the pre-rerank cosine, so a bad reranker can degrade order but never cause a false serve, a skipped build, or a broken null refusal.
- claim_index protocol — BYO pool storage (built-in numpy / pure-python implementations; per-namespace factory form supported).
- New events: pool_gate, pool_served, pool_masked_stale, pool_budget_overrun, rerank_failed, rebuild_triggered_by_read, build_triggered_by_gap, unit_marked_lossy, unit_repaired, residual_served, residual_fallback, key_attached, key_confirmed, key_fired.
- Constructor guards that fail loud: query_keys=True without read_path="pool" raises ValueError (keys would attach but structurally never fire); read_path="pool" under the lexical HashingEmbedder raises at construction (claim cosine collapses to keyword overlap).
Changed- serve_budget default split: None → 600 on the unit path (v0.5 preserved) and 1000 on the pool path (the measured ~1,036-token operating point under strict header-counting packing). Explicit values always win; <= 0 raises.
- Result contract on the pool path (unit path untouched): understanding = {"claims": [...]} with no summary key; unit_id = owner of the top-ranked served claim; confidence = pre-decision pool coverage; evidence = [] on a non-escalated serve (cite via drill(unit_id)); pool = served claims in served order; cache_hit = zero synthesis calls ran this read.
- stats() pool additions: pool_serves, probe_reads, admission_reuses, retrievals, rebuilds_by_read, builds_by_gap, serve_gate_effective, pool_noise_ceiling, pool_claims_fresh, pool_claims_total, avg_units_per_serve, pool_scan_slow.
Fixed- v0.5 pool-preview stale-serve hole: the preview's (len, xor-hash) pool marker could return to its prior value after an in-place rebuild within one read, serving the old claim texts. Replaced by two monotone counters; a same-size rebuild can no longer restore a prior marker value. If you never set serve="pool", this never affected you.
Deprecated- serve="pool" (the v0.5 experimental preview): preserved verbatim in 0.6, never auto-mapped to read_path="pool"; removal was scheduled for v0.7 at the time — superseded by the 0.7.0 flip-gate status above: the flip was not taken, the preview survives unchanged, and no unit-path read knob warns yet. The unit-path read knobs (hit_threshold, hit_margin, route_by_claim, recall_*, select_floor, ...) are inert on the pool path and keep full function on the default path.
- v0.5.0July 2026
The pool release.
Added- preset="multi_hop" — one argument arms cross-unit recall + the hop-2 bridge with calibrated thresholds; explicit kwargs still override. Replaces the manual recall_threshold=0.7 guidance.
- Source widening — widen_chunks: miss-triggered builds read up to N chunks of the dominant source (a duck-typed retriever.widen(artifact_id, limit=) or a BYO source_fetcher) instead of the retrieval keyhole; never fires at ingest. widen_on_admission (follows widen_chunks) rebuilds thin-coverage admissions widened in place. In the cold-start pilot, widened units read a median 23 chunks of their source vs 2 for keyhole builds, and rebuild churn fell 460 → 31.
- provenance_admission — an exact-text containment probe before any build: covered reads serve without building (duplicate-understanding prevention). Admission reuse ×4 in the pilot.
- split_by_artifact — one unit per source when retrieval mixes artifacts.
- adaptive_hit — the hit gate self-calibrates against cross-unit score inflation as the cache grows; repeat/paraphrase queries keep hitting via the seed-reuse channel.
- recall_bridge / bridge_limit — a hop-2 bridge restart: rank other units' claims by similarity to the matched unit's own claims. Armed by preset="multi_hop".
- serve="pool" (experimental preview of the v0.6 read path) — serve the token-budgeted, globally-ranked fresh-claim pool (serve_budget, default 600, is the cost dial; pool_header supplies per-unit header lines); renderers read result.context["pool"]; stale units' claims are masked the moment a source changes. Measured on MultiHopRAG (real news, pre-registered, held-out n=605): 0.699 accuracy @ ~1,040 context tokens vs 0.579 for the unit path (paired-test z = 6.66); statistically ties naive dense RAG's best measured arm at 0.79x its tokens — we do not claim to beat it there; 95% refusal honesty on unanswerable questions (naive 85–88%).
- fast="auto" — a numpy-accelerated read path (pip install "coalent[fast]") with identical results (CI-pinned equivalence); the pure-Python fallback keeps the zero-dependency core.
- on_event — structured freshness events: unit_built, unit_rebuilt, admission_reuse, admission_widen_rebuild, stale_read_prevented, claims_recalled, bridge_claims, source_changed.
- Result.needs_retrieval — a hint that coverage fell below the floor.
Changed- select_floor is deprecated — superseded by pool serving (serve="pool"), which ranks and budgets claims globally instead of trimming per unit.
- v0.4.0July 2026
Extractive understanding and cross-unit recall — now the defaults.
Added- Cross-unit claim recall (cross_unit_recall, on by default) — when the matched unit under-covers a query, Coalent pools per-claim memory across all fresh units (MaxSim) and surfaces the bridge facts a single unit can't, answering multi-hop questions naive retrieval structurally can't (0% → 100% on the multi-hop benchmark) at zero extra LLM calls. Dormant and free on single-hop reads; auto-disabled under a non-semantic embedder. recall_threshold=None inherits coverage_floor; set ~0.7 for full multi-hop. Escape hatch: cross_unit_recall=False.
- result.recalled — the surfaced cross-unit claims, a list of RecalledClaim(claim, score, unit_id). Empty when recall didn't fire (single-hop hits, or a non-semantic embedder).
- hit_margin (default 0.0, off) — refuse ambiguous ties: if the top unit doesn't beat the runner-up by the margin, build the query's own unit instead of serving a coin-flip. For contradiction / collision-heavy corpora; leave off on clean data.
- select_floor (default off) — serve atoms by meaning: emit only the claims whose per-claim cosine to the query clears the floor, for fewer tokens on paraphrase-heavy reads over large units.
- residual_floor (build-time, default off) — keep number-bearing spans the extractor dropped (capped by residual_limit, default 24), for messy real prose.
- EXTRACTIVE_INSTRUCTION exposed on LLMSynthesizer — the default query-independent extraction prompt, to inspect or override.
Changed- Extractive understanding is now the default — LLMSynthesizer(extract=True). A unit's understanding is a query-independent list of atomic, source-grounded claims (understanding["claims"]) instead of a question-shaped prose summary, so one unit answers many later questions and keeps every number (prose dropped ~40% of numbers in tests). understanding["summary"] may be terse or empty. Escape hatch: extract=False restores exact 0.3 prose.
- On upgrade, cached understanding is now claims, not prose — units re-materialize into the extractive shape on their next read.
- v0.3.0June 2026
Understanding-keyed matching, semantic coverage, and tunable thresholds.
Added- Understanding-keyed matching — blends a topic score (query ↔ the unit's understanding) with the seed score (query ↔ the original query), weighted by understanding_weight (default 0.7). Kills surface-form false hits ("exchange policy" no longer hits "leave policy") while keeping paraphrase recall.
- Semantic per-claim coverage + escalation — a hit whose best claim under-covers the query escalates to fresh raw (the "never less than plain retrieval" floor, now semantic). Tunable via coverage_floor and enable_coverage_escalation; surfaced as result.coverage and result.escalated.
- Pluggable coverage_scorer + two-tier coverage_ceiling — cosine stays the zero-dep default; plug a cross-encoder / NLI / LLM-entailment check for containment, consulted only on borderline queries.
- Per-claim routing (route_by_claim) — optional late-interaction matching by the unit's best-matching claim.
- Embedder-aware default thresholds + calibrate_thresholds (labeled) and suggest_thresholds (labels-free).
- relevance_gate — a (query, chunks) -> chunks hook applied before synthesis (bring your own reranker).
- Depth knob on LLMSynthesizer (0.0–1.0) — trade synthesis cost against coverage completeness.
- Batch embeddings (embed_many), behavioral hit_queries, and richer stats() (reads, hits, escalations, escalation_rate, hit_rate).
Changed- coverage_floor is now a semantic max-per-claim cosine (was a lexical token-overlap fraction); hit_threshold gates the blended score and auto-derives per embedder.
- A unit's identity is its understanding — the seed query no longer drifts when a unit is rebuilt.
Removed- The lexical coverage gate — replaced by semantic per-claim coverage.
- v0.2.1June 2026
Smart embeddings — semantic cache hits out of the box.
Added- OpenAIEmbedder and FunctionEmbedder, plus a smart default that auto-uses OpenAI embeddings when coalent[openai] is installed and OPENAI_API_KEY is set — otherwise a lexical HashingEmbedder fallback with a warning.
- v0.2.0June 2026
First public release — a provenance-invalidated cognitive cache for AI agents and RAG.
Added- SemanticCache.get() — an embedding-keyed cache of decision-ready understanding that retains the raw evidence with every unit, so it can never return less than plain retrieval.
- Provenance invalidation — source_changed / source_deleted dirty only the units that used a source, and skip no-op changes via a content-hash compare; units re-materialize lazily on read.
- Retrievers (InMemory, Function, Composite, BaseVector) + bring-your-own-client adapters for Qdrant, Chroma, and pgvector.
- Synthesizers — LLMSynthesizer (citation-grounded) and JSONPassthroughSynthesizer (no LLM call); OpenAI / Anthropic / stub providers.
- Context intelligence, FreshnessPolicy (TTL + revalidate), persistence (SQLite / Redis), event connectors, LangGraph + MCP helpers, a CLI, and an eval harness.
The machine-readable source lives in CHANGELOG.md in the repository.