Searchable Feature gallery

ADR-0005: What's core (always bundled) vs. opt-in (separately gated)

Status

Accepted for the boundary as it exists today. The full dynamic plugin registration system in archive/specs/plugin-architecture.md / archive/specs/plugin-api.md remains a draft spec, not built — this ADR is about the boundary decision already made and shipped, not the future registration mechanism.

2.0 amendment: vector search and binary shard codecs were removed. The single @ktjn/searchable bundle contains the complete lexical runtime; only feature data such as synonym and fuzzy shards remains lazy-loaded.

Context

The overview's small-core goal and the 15 KB gzip bundle budget (Project governance) require a decision about which features every consumer pays for versus which are opt-in. Two genuinely different mechanisms exist in this codebase for "opt-in" and conflating them would misdescribe the system.

Decision

Two distinct opt-in mechanisms, chosen per feature by its actual cost shape, not one uniform plugin system:

  1. Baked-in-but-inert-until-used (facets, synonyms, pins, fuzzy matching): shipped in the one @ktjn/searchable bundle unconditionally — pnpm size's 15 KB budget is measured against this bundle including all of them. These stay small enough in code size that separate bundle-splitting isn't worth the complexity yet; the data for each (a synonym shard, a fuzzy shard) is still fetched lazily only when a query needs it, so the runtime cost is opt-in even though the code isn't.
  2. Genuinely separate, lazy-loaded dependency (removed in 2.0): previously used for @huggingface/transformers-backed embedding. The pattern remains valid for any future heavy dependency (a multi-MB model, a codec only some deployments need).

A real dynamic plugin registration API (third-party analyzers/ranking/ storage backends registering themselves, per archive/specs/plugin-architecture.md's contract) is explicitly not required for 1.0 — see the roadmap.

Alternatives Considered

Consequences