Skip to content
Menu

Documentation

Add your own capability

A backend with no matching capability needs a contract of its own. Split the package in two, so a module can import the contract without the driver:

vector_index/contracts.py
"""What a module may import: the caller's Protocol, the reference and the spec."""

import abc
from typing import ClassVar, Protocol

from sandloom.driverkit import CapabilityRef, CapabilitySpec, InfraProvider


class VectorIndex(Protocol):
    async def nearest(self, vector: list[float], *, limit: int) -> list[str]: ...


class VectorIndexProvider(InfraProvider, VectorIndex):
    capability: ClassVar[str] = "vector_index"

    @abc.abstractmethod
    async def nearest(self, vector: list[float], *, limit: int) -> list[str]: ...


VECTOR_INDEX: CapabilityRef[VectorIndex] = CapabilityRef("vector_index.v1")

VECTOR_INDEX_SPEC = CapabilitySpec(
    name="vector_index",
    version="v1",
    provider_contract=VectorIndexProvider,
    features=frozenset({"exact"}),
    stability="experimental",
)
vector_index/driver.py
"""The driver: a module may not import this."""

from vector_index.contracts import VectorIndexProvider


class MemoryVectorIndex(VectorIndexProvider):
    contract_version = "v1"
    supported_features = frozenset({"exact"})

    async def nearest(self, vector: list[float], *, limit: int) -> list[str]:
        # "exact": a linear scan of everything, never an approximation.
        return ["a", "b"][:limit]
pyproject.toml
[project.entry-points."sandloom.capabilities"]
vector_index = "vector_index.contracts:VECTOR_INDEX_SPEC"

[project.entry-points."sandloom.drivers"]
"vector_index.memory" = "vector_index.driver:MemoryVectorIndex"
  • Selecting it: INFRA={"vector_index":{"default":{"driver":"memory"}}}.
  • Requiring it from a module: CapabilityRequirement("vector_index", features=frozenset({"exact"})) in define_module. Startup then fails, without I/O, if it is missing.
  • Calling it from a module: the reference carries the type, as long as your package ships a py.typed file. Without one, type checkers see Any.

    from sandloom.sdk.infra import capability  # sandloom: advanced infra
    from vector_index.contracts import VECTOR_INDEX
    
    nearest = await capability(VECTOR_INDEX).nearest([1.0], limit=5)
    
  • What a module may import: vector_index.contracts. Importing vector_index.driver or its parent vector_index, which reaches the driver by attribute, fails SANDLOOM-C004, because an entry point names that module.

  • In production: stability="experimental" requires the accepted risk experimental_capability (SANDLOOM-B023). Use "stable" when you keep the contract stable yourself.
  • Reserved names: the kernel defines search, document_store, graph_store, workflow, lock and secrets, so a package cannot declare them.

See also Write a driver and the driver kit.