Analyzer Plugins¶
Analyzer plugins must return an object implementing
codira.contracts.LanguageAnalyzer.
The smallest working example lives at
examples/plugins/codira_demo_analyzer.
Required attributes and methods:
name: strversion: strdiscovery_globs: tuple[str, ...]supports_path(path: Path) -> boolanalyze_file(path: Path, root: Path) -> AnalysisResult
Concurrent indexing is opt-in for plugins. Implement
analyzer_concurrency_declaration() and return an
AnalyzerConcurrencyDeclaration to permit process or thread workers. Thread
support also requires reentrant_after_configure = True. Plugins without this
declaration remain serial in auto mode; explicit concurrent modes reject an
active undeclared plugin before backend initialization.
Minimal example:
from pathlib import Path
from codira.contracts import LanguageAnalyzer
from codira.models import AnalysisResult, ModuleArtifact
class DemoAnalyzer:
name = "demo"
version = "1"
discovery_globs = ("*.demo",)
def supports_path(self, path: Path) -> bool:
return path.suffix == ".demo"
def analyze_file(self, path: Path, root: Path) -> AnalysisResult:
relative = path.with_suffix("").relative_to(root)
module_name = ".".join(relative.parts)
return AnalysisResult(
source_path=path,
module=ModuleArtifact(
name=module_name,
stable_id=f"demo:module:{relative.as_posix()}",
docstring=None,
has_docstring=0,
),
classes=(),
functions=(),
declarations=(),
imports=(),
)
def build_analyzer() -> LanguageAnalyzer:
return DemoAnalyzer()
Register it in pyproject.toml:
[project.entry-points."codira.analyzers"]
demo = "codira_demo_analyzer:build_analyzer"
Rules:
- analyzer names must be unique across registered plugins
- duplicate names are rejected deterministically
- analyzers participate in deterministic discovery order
- analyzer discovery globs must be stable and sufficient for scanner candidate discovery
- scanner discovery confirms ownership through
supports_path(path)before a file enters the indexing set, so broad globs are allowed only whensupports_path()deterministically rejects unsupported files - analyzers must emit stable IDs that are unique within one returned
AnalysisResult; if a language can produce same-name collisions in one file, the analyzer must disambiguate them deterministically before returning - when
[index.coverage]does not overrideroots, the coverage audit uses the deterministic union of the roots declared by active analyzers; the first-party Python analyzer defaults tosrc/,tests/, andscripts/ - configured
rootsreplace the analyzer defaults, whileroots = ["-"]disables coverage auditing; see Coverage roots - configured
exclude_suffixessilence intentionally unsupported tracked file types after root selection, for example.yml,.dot,.js, or.svg codira covis the operator-facing way to verify whether your analyzer closes those gaps- analyzers must not own storage or query persistence