Plugin Model¶
ADR-004 landed the analyzer/backend plugin surface. ADR-022 extends that
model with embedding engine and vector-store plugin families.
Accepted Target Model¶
The accepted migration now distinguishes five extension families:
IndexBackend: exactly one active storage/query backend per repository indexLanguageAnalyzer: zero or more analyzers participating in one indexing runEmbeddingEngine: exactly one active text-to-vector runtimeVectorStore: exactly one active vector persistence/similarity storeDocumentationAuditPlugin: zero or more convention-specific documentation validators selected by explicit routes
This asymmetry is deliberate:
- storage selection is an instance-level policy
- analyzers represent repository-content capabilities
- embedding engines and vector stores are singleton runtime/storage choices because vector identity and query ranking depend on the active pair
- documentation audit plugins may overlap by language, so activation is an explicit language/convention/path routing decision instead of an implicit analyzer side effect
Current State¶
The current codebase now exposes:
- first-party backend and analyzer package registrations
- third-party plugin discovery through Python entry points
- deterministic duplicate rejection and load diagnostics
- a
codira pluginsinspection surface for discovery verification - optional explicit configuration injection through
configure(config) - optional plugin-owned JSON Schema publication through
configuration_json_schema() - machine-readable capability reporting for all five plugin families through
codira caps --json
Phase-3 Baseline¶
Phase 3 now introduces the first explicit contract modules:
src/codira/contracts.pysrc/codira/models.pysrc/codira/normalization.py
Those modules define the accepted vocabulary for:
LanguageAnalyzerIndexBackend- normalized
AnalysisResultartifacts
Phase-8 Registries and Configuration¶
Phase 8 introduced explicit registry helpers in src/codira/registry.py.
-
Current defaults and selection rules are:
-
effective configuration selects the active backend through
[backend].name CODIRA_INDEX_BACKENDremains a process override forbackend.name- when unset or blank across all config levels, the backend defaults to
sqlite - unsupported backend names raise
ValueErrorbefore indexing or query work - analyzers are registered from first-party packages plus entry points and instantiated in deterministic order
[plugins].disabled_analyzersremoves configured analyzers from the active analyzer set[plugins].disable_third_partydisables third-party plugin loading- file routing still uses first-match analyzer selection
This keeps configuration narrow while making backend selection and analyzer activation explicit.
Configuration Injection Contract¶
Plugins never read global config directly. The registry extracts the namespaced table for each loaded plugin and injects it into fresh plugin instances:
[plugins.analyzer-python]
emit_imports = false
exclude_paths = ["tests/fixtures"]
The table name is plugins.<family>-<plugin-name>, where <family> is
analyzer, backend, embedding, vector-store, or
documentation-audit.
Plugins may expose:
def configuration_json_schema(self) -> Mapping[str, object]: ...
def configure(self, config: Mapping[str, object]) -> None: ...
Both hooks are optional for third-party plugins. A plugin without a schema is
not schema-validated beyond the core table shape. A plugin without
configure() keeps default behavior; if its table contains settings other than
enabled, codira config validate reports a non-fatal warning.
First-party plugins expose strict schemas with additionalProperties = false.
All plugin tables accept enabled: bool = true. Analyzer tables also accept
repo-relative include_paths and exclude_paths, evaluated after suffix or
family eligibility; excludes take precedence over includes.
Configured analyzer state contributes to persisted analyzer inventory through a deterministic configuration fingerprint. Changing analyzer configuration therefore invalidates stale index reuse without hidden global state.
The current packaging boundary is also now explicit:
- core
codiradependencies cover shared CLI, registry, query, indexing, and contract infrastructure - analyzer-specific dependencies live in separate plugin distributions
- the current Python, JSON, C, C++, and Bash analyzers are extracted into first-party packages rather than remaining built-ins in the core install
- the default SQLite backend is provided by
codira-backend-sqlite - the optional DuckDB backend is provided by
codira-backend-duckdb - the default SentenceTransformers engine is provided by
codira-embedding-sentence-transformers - the optional ONNX Runtime engine is provided by
codira-embedding-onnx - local vector-store plugins are provided by
codira-vector-store-sqliteandcodira-vector-store-duckdb - first-party documentation audit plugins are provided by
codira-documentation-audit-numpy,codira-documentation-audit-google, andcodira-documentation-audit-doxygen - documentation audit plugin implementations are loaded from package entry points; core only owns the shared contract and route execution boundary
- third-party plugins live in separate distributions and are discovered from
codira.analyzers,codira.backends,codira.embedding_engines,codira.vector_stores, andcodira.documentation_auditsentry-point groups
Documentation Audit Routing¶
Documentation audit plugins are intentionally separate from language analyzers. Analyzers decide which source files and artifacts are indexed; documentation audit plugins decide whether an indexed documentation block satisfies one documentation convention.
Routes live in plugins.documentation_audit_routes. Each route declares:
language: analyzer language such aspython,c, orcppconvention: convention label passed to the plugin, such asnumpy,google, ordoxygenplugin: plugin name selected from the documentation-audit registry- optional
include_pathsandexclude_pathsrepo-relative glob patterns
More than one documentation audit plugin can be installed for the same
language. Codira therefore does not auto-select a convention. During indexing,
a public artifact is audited only when exactly one route matches its language
and path. No route means no documentation audit row is emitted; more than one
matching route emits an ambiguous_route diagnostic so operators can tighten
the route table.
The first release scope supports:
- NumPy-style Python docstrings through plugin
numpy - Google-style Python docstrings through plugin
google - Doxygen-style C and C++ comments through plugin
doxygen
Phase-9 Analyzer Proof¶
Phase 9 validated the analyzer side of the plugin model with a second implementation. The current package set extends that proof:
PythonAnalyzerhandles*.pyJSONAnalyzerhandles supported JSON document familiesCAnalyzerhandles*.cand*.hCppAnalyzerhandles standard C++ source and header suffixesBashAnalyzerhandles Bash scripts- all active analyzers can participate in the same indexing run
This is the first concrete proof that the LanguageAnalyzer contract supports
mixed-language repositories without changing backend semantics.