v2.3.0 — Pluggable LLM providers, MCP module, SEO foundations
[2.3.0] - 2026-04-17
Pluggable LLM provider infrastructure (RFC-002 Phase 1), MCP server
as a first-class Python module, PyPI discoverability refresh, SEO
foundations across the docs site, and a full docs-vs-code
reconciliation. All additions are backward-compatible; no existing
API changes. Supersedes the never-tagged 2.2.1 metadata patch —
its PyPI classifier / keyword / image-URL changes are folded in
below.
Added
- Pluggable LLM provider infrastructure (RFC-002 Phase 1) — new
zettelforge.llm_providerspackage with a@runtime_checkable
LLMProviderprotocol, a thread-safe registry, and built-in
providers forlocal(llama-cpp-python),ollama, andmock.
The publicgenerate()signature is unchanged; all 7 existing call
sites (fact_extractor,memory_updater,synthesis_generator,
intent_classifier,note_constructor,entity_indexer,
memory_evolver) keep working without modification. Third-party
providers can register via thezettelforge.llm_providers
entry-point group.openai_compatandanthropicproviders land
in Phase 2 and Phase 3. LLMConfigexpanded — newapi_key,timeout,max_retries,
fallback, andextrafields.api_keysupports${ENV_VAR}
references and is redacted fromrepr(). Sensitive keys inside
extra(matchingkey|token|secret|password|credential|auth) are
redacted as well. New env overrides:ZETTELFORGE_LLM_API_KEY,
ZETTELFORGE_LLM_TIMEOUT,ZETTELFORGE_LLM_MAX_RETRIES,
ZETTELFORGE_LLM_FALLBACK.LLMProviderConfigurationError— new exception surfaced for
non-recoverable provider setup problems (bad API key, missing
optional SDK) sogenerate()can distinguish "try the fallback"
from "stop and report".llm_client.reload()helper — clears the provider registry
and config cache so test suites and long-lived processes can
reconfigure the LLM backend without a process restart.- Hardened .gitignore per GOV-023 — added
.env.*,*.key,
*.pem. - MCP server as a first-class module —
python -m zettelforge.mcp
now works out of apip install zettelforgewith no git clone
required. New packagezettelforge.mcp(withserver.py,
__main__.py, and a console-script entryzettelforge-mcp).
The previous entry point atweb/mcp_server.pyis retained as a
thin backward-compat shim. - Console scripts —
zettelforgeandzettelforge-mcpentry
points added topyproject.toml. - How-to guides — migration (
migrate-jsonl-to-sqlite.md),
benchmark reproduction (reproduce-benchmarks.md), troubleshooting
(troubleshoot.md), and upgrade (upgrade.md). Linked from the
MkDocs nav. - Design and About sections in the docs nav — RFC-001, RFC-002,
RFC-003 and the origin-story narrative are now discoverable from
docs.threatrecall.ai. - RFC-003 design proposal (docs only) — read-path depth routing
with a deterministic Quality Gate plus System 1 / System 2 recall
paths. Ships with an adversarial-review artifact (4 blockers, 13
warnings). No runtime changes yet — implementation deferred. - Archive directory —
docs/archive/holds retired v1.0.0-alpha
snapshots (SKILL.md,PACKAGE_SUMMARY.md) with a README explaining
their provenance. llm_nerconfiguration reference —docs/reference/configuration.md
now documentsllm_ner.enabledand theZETTELFORGE_LLM_NER_ENABLED
environment override.- Docs SEO foundation — per-page canonical URLs, OpenGraph and
Twitter-card metadata, and aSoftwareApplicationJSON-LD block on
the home page via adocs/overrides/main.htmltheme override. The
softwareVersionvalue is sourced fromconfig.extra.versionin
mkdocs.ymlso it stays in sync with releases. - PyPI classifier refresh — added
Topic :: Security(primary
filter security engineers use to browse PyPI) and
Topic :: Software Development :: Libraries :: Python Modules.
ExistingTopic :: Scientific/Engineering :: Artificial Intelligence
retained. Development Status stays at4 - Beta. - PyPI keyword refresh — swapped
agent-memory→agentic-memory
(emerging category keyword) andzettelkasten→llm-memory
(direct intent match for Mem0/Graphiti discovery traffic). Still
10 keywords total; within the PyPI display limit.
Changed
- SECURITY.md — contact updated to
contact@threatrecall.ai,
supported-versions table refreshed to mark2.3.xas current and
2.2.xas the prior minor release; storage section refreshed to
reflect SQLite-by-default. docs/llms.txt— rewritten to match current reality (SQLite
default, 19 runtime entity types, correct GOV-003/007/011/012
descriptions, MCP invocation).- BENCHMARK_REPORT.md — CTIBench ATE row updated (F1 = 0.146);
architecture summary reframed as SQLite + LanceDB default with
TypeDB as an extension;ctibench_results.jsondate bumped. - README — above-fold rewritten (CTA row, keyword density,
PyPI-safe absolute-URL images). Pipeline step 1 entity count
corrected from "10 types" to the 19 typesEntityExtractor
actually recognises. - README image paths —
docs/assets/demo.gifand
docs/assets/zettelforge_architecture.svgrewritten to absolute
raw.githubusercontent.comURLs so the PyPI long description
renders correctly (relative paths 404 on the PyPI CDN). Pinned to
themasterref; can be re-pinned to thev2.3.0tag in the
next release PR if PyPI-side stability matters. docs/superpowers/plans/renamed todocs/superpowers/research/
with a README making clear these are aspirational synthesis, not
roadmap commitments. The stray untrackeddocs/plans/directory
was removed.- Tutorials and governance-controls reference —
last_updated
andversionmetadata refreshed. zettelforge.ontologyexports —TypedEntityStore,
OntologyValidator,get_ontology_store,get_ontology_validator
removed from the top-level__all__(still importable from
zettelforge.ontology). They are a parallel store not wired into
MemoryManager.observability.pyandcache.pyheaders — annotated as
currently unwired; kept for future integration.- OCSF
_PRODUCT_VERSION— sourced from
importlib.metadata.version("zettelforge")instead of a hard-coded
string, so emitted OCSF events stop drifting when__version__
bumps. - OpenGraph
og:type—websiteon the home page,article
elsewhere (was unconditionallyarticle).
Fixed
- OllamaProvider host routing — now instantiates
ollama.Client(host=self._url)so the configured URL actually
takes effect (previously the module-levelollama.generate()call
ignored per-instance host). - Provider registry race —
register()now checks and mutates
under the registry lock, closing a TOCTOU window on concurrent
provider registration. - MCP server lazy instantiation —
MemoryManageris now created
on first tool call rather than at server import time, so--help
and protocol-handshake tests don't pay the model-load cost.
Removed
- Six superseded branches that had already been squash-merged into
master —feat/causal-chain-fix-and-demo-gif,
feat/entity-vocabulary-expansion,
feature/RFC-001-conversational-entity-extractor,
fix/intent-classifier-graph-weight,
fix/p0-production-blockers,feat/remember-evolve.