Architecture Plan¶
This page records the local plan for vendor-fabric. It is the source
of truth for provider and vendor architecture in this repository.
Boundary¶
vendor-fabric owns vendor behavior for the Extended Data stack:
provider discovery and availability reporting
vendor connector base classes
provider-specific SDK adapters
capability dispatch for files, secrets, identity, billing, messaging, and other vendor surfaces
provider-backed sync operations
Python SecretSync binding facade capabilities
pytest support for vendor/provider tests
extended-data owns base data primitives, containers, input handling,
logging, files, and generic workflows. agentic-fabric owns agent
runtime orchestration.
Runtime orchestration, crew discovery, framework runner selection, and
agent fixtures are not part of this package. Provider modules may expose
plain capability functions, schemas, and metadata; framework-specific
tool factories live in agentic-fabric.
VendorData¶
VendorData is the public data facade for this package. It inherits
from extended_data.ExtendedData and extends that data behavior with
provider state.
The outer VendorData object owns provider context. Its internal
_data value owns the current extended shape. The facade owns a
ConnectorFabric (created lazily when none is supplied), an optional
logger exposed as logging (falling back to the fabric’s logger), a
declared-capability tuple, and an active-provider id available through
the read-only active_provider property.
from extended_data import ExtendedData
from vendor_fabric.connectors import ConnectorFabric
class VendorData(ExtendedData):
def __new__(cls, value=None, *, fabric=None, logger=None,
capabilities=(), **fabric_kwargs):
return object.__new__(cls)
def __init__(self, value=None, *, fabric=None, logger=None,
capabilities=(), **fabric_kwargs):
self._data = ExtendedData(value)
self.fabric = fabric or ConnectorFabric(
logger=logger, **fabric_kwargs)
self.logging = logger or getattr(self.fabric, "logging", None)
self._declared_capabilities = tuple(capabilities)
self._capability_index = _index_capabilities(
self._declared_capabilities)
self._provider_capability_cache = {}
self._providers = {}
self._unavailable = {}
self._active_provider = None
@property
def value(self):
return self._data
@property
def active_provider(self):
return self._active_provider
def cast(self, value):
self._data = ExtendedData(value)
return self
This preserves the ExtendedData contract while letting the vendor
layer add provider-aware operations. Operations take the provider id as
their first positional argument and dispatch to the connector method
declared in the capability matrix, falling back to the active provider
when none is given:
from vendor_fabric.vendor_data import VendorData
data = VendorData({"resource": "config"})
data.open("aws")
data.call("get_object", "aws", bucket="my-bucket", key="config.json")
github = VendorData(fabric=fabric).open("github",
github_owner="jbcom",
github_repo="extended-data")
github.call("get_repository_file", "github", file_path="README.md")
VendorData also exposes two helpers for inspecting support: the
capabilities(provider=None) method returns the full route set (or
one provider’s routes), and capability_matrix() returns an
operation -> provider -> route mapping. Use supports(provider,
operation) to query a single route. There is no __dir__ override;
caller-side autocomplete reflects the static API plus whatever
open_<provider> lambdas __getattr__ synthesises.
Provider Capability Registry¶
Provider support should be declared on provider classes, not hardcoded as a large repeated pass-through method matrix.
Use normal Python mechanisms:
abstract base classes for common connector behavior (
vendor_fabric.base.ConnectorBasemixes inCapabilityProviderMixin)a
@capability(...)decorator on provider methods; decorated methods carry a_vendor_capabilitiestuple ofCapabilitySpecrecordsCapabilityProviderMixin.__init_subclass__to collect decorated methods from the full method resolution ordera
capabilitiesmapping (vendor_capabilities/vendor_capability_methods) on provider classes for inspection and dispatch__getattr__onVendorDataonly as a thin convenience for the declared operations (open_<provider>and the bare operation name)
Connectors may also declare a __supports__ mapping on the class to
publish additional operation aliases that are not themselves decorated
methods (for example, mapping "get_file" to a concrete
get_object method). VendorData.declare_supports attaches this
metadata; the _declared_supports helper reads it back. Use ordinary
metadata such as _vendor_capabilities on decorated methods and
__supports__ on provider classes.
class AwsConnector(ConnectorBase):
@capability("get_file", kind="files", aliases=("read_file",))
def get_object(self, bucket: str, key: str):
...
VendorData resolves operations by:
checking whether the caller supplied a provider id as the first argument
otherwise using the active provider opened by
open(provider_id)otherwise finding a single available provider that supports the capability
raising a clear ambiguity or unavailable-feature error
Optional Dependencies¶
Core imports stay lightweight. Provider extras install SDKs:
vendor-fabric[aws]vendor-fabric[google]vendor-fabric[github]vendor-fabric[slack]vendor-fabric[vault]vendor-fabric[zoom]vendor-fabric[meshy]
Unavailable providers should appear as unavailable in the registry with install guidance. Normal consumer code should not need repeated import juggling.
Secret Sync¶
SecretSync execution semantics belong to jbcom/secrets-sync. This
repository owns the Python facade over the gopy binding, credential
handoff, redaction, Extended Data-shaped payloads, and provider
capability metadata. Native Python helpers in this package are
transitional compatibility scaffolding and should not grow into a second
pipeline implementation.
Testing Package¶
pytest-vendor-fabric is a sibling package in this repository. It
provides connector fixtures, a mock logger, credential guards, the
e2e marker, and the --e2e opt-in control for live E2E tests.
Agent runtime fixtures belong in pytest-agentic-fabric, not here.
Validation Contract¶
Every public behavior needs tests and docs in the same change. Python 3.11, 3.12, 3.13, and 3.14 must pass without skipped missing interpreters.