Contributing a New Language Adapter Pack
This guide explains how to add a new language pack to the Bitloops language-adapter runtime without changing DevQL core dispatch code.
1) Implement the LanguageAdapterPack contract
The runtime contract lives in:
bitloops/src/host/language_adapter/pack.rs
A new pack must implement:
descriptor()-> returns aLanguagePackDescriptorcanonical_mappings()-> mapping table from typedLanguageKindvariants to canonical projectionssupported_language_kinds()-> complete supported typedLanguageKindsetextract_artefacts(content, path)-> language symbol extractionextract_dependency_edges(content, path, artefacts)-> dependency graph extraction
Optional lifecycle hooks:
extract_file_docstring(content)(defaultNone)test_support()(defaultNone)migrations()(default[])health_checks()(default[])
If the language pack should support test_harness, implement the reusable LanguageTestSupport facet under the adapter pack instead of adding language-specific code under capability_packs/test_harness.
2) Canonical mapping rules and projections
Canonical mapping types live in:
bitloops/src/host/language_adapter/canonical.rs
Rules:
- Canonical mapping is table-driven (
CanonicalMapping), not match-block code in DevQL. - Every
CanonicalMapping.language_kindmust appear insupported_language_kinds(). MappingCondition::WhenInsideParentoverridesAlwayswheninside_parent == true.- Some language kinds may intentionally have no canonical projection (language-specific-only artefacts).
- Adapter internals should use typed
LanguageKindvalues rather than raw string literals. - Convert
LanguageKindto strings only at persistence or public API boundaries viaas_str().
Projections are defined in:
bitloops/src/host/devql/core_contracts.rs(CanonicalKindProjection)
3) LanguageArtefact and DependencyEdge type contracts
Shared types are defined in:
bitloops/src/host/language_adapter/types.rs
Key expectations:
LanguageArtefact.symbol_fqnmust be stable and unique per symbol within file scope.parent_symbol_fqnshould be set for nested symbols (methods, members, etc).canonical_kindshould be populated by extractor mapping when a canonical projection exists.language_kindis a typedLanguageKind, not a raw parser string.DependencyEdgemust include accurateedge_kind, source symbol, and either target symbol fqn or unresolved reference.metadatashould preserve edge-resolution and form details (import,call,export,refforms).
4) Step-by-step: add a hypothetical Python pack
Create modules using file+folder sibling pattern (no mod.rs root files):
bitloops/src/adapters/languages/python.rsbitloops/src/adapters/languages/python/pack.rsbitloops/src/adapters/languages/python/extraction.rsbitloops/src/adapters/languages/python/edges.rsbitloops/src/adapters/languages/python/canonical.rs
Update registry factory:
bitloops/src/adapters/languages.rs
Actions:
- Define
PythonKindvariants inbitloops/src/host/language_adapter/kinds.rs. - Define
PYTHON_CANONICAL_MAPPINGSandPYTHON_SUPPORTED_LANGUAGE_KINDSinpython/canonical.rsusing typedLanguageKind::python(...)values. - Implement symbol extraction in
python/extraction.rsreturningVec<LanguageArtefact>with typedlanguage_kindvalues. - Implement dependency extraction in
python/edges.rsreturningVec<DependencyEdge>. - Implement
PythonLanguageAdapterPackinpython/pack.rs. - Expose module root in
python.rs. - Register pack in
builtin_language_adapter_packs()inlanguages.rs.
No DevQL dispatch changes should be required.
5) Testing strategy for new packs
Required checks:
- Canonical mapping table coverage tests (supported kinds and projected kinds).
- Artefact extraction tests for representative constructs and edge cases.
- Dependency edge tests for imports/exports/calls/references and dedup/order behavior.
- Registry integration test (
LanguageAdapterRegistry) for pack registration and execution. - String round-trip tests for any new language-specific
LanguageKindvariants.
Recommended targeted commands:
cargo check -p bitloops
cargo nextest run -p bitloops --lib --no-capture -- host::devql::mapping_tests --exact
cargo nextest run -p bitloops --lib --no-capture -- extraction_<your_language> --exact
6) Where registration happens
Built-in language adapter registration is centralized at:
bitloops/src/adapters/languages.rs->builtin_language_adapter_packs()
Runtime registry initialization is in:
bitloops/src/host/devql.rs->language_adapter_registry()
devql packs language-adapter lifecycle/reporting is also assembled in host/devql.rs.
7) Optional test-support facet
If the language pack needs to support structural test discovery, add a test_support.rs implementation under the adapter pack and return it from test_support().
Recommended shape:
bitloops/src/adapters/languages/<your_language>/test_support.rs
The shared contract lives under:
bitloops/src/host/language_adapter/test_support.rs
Use that facet for:
- test-file classification
- source discovery
- optional runtime enumeration
- reconciliation of source and enumerated scenarios
Do not add new language-specific parsers under capability_packs/test_harness for new language work.