Resource providers
Installed Python distributions can add providers through the
ridge.providers entry-point group:
The callable receives the configured name, the provider-owned mapping without
the core-owned provider and lock_key fields, and a ProviderContext. It returns
a resource composed from Ridge's existing capabilities:
from collections.abc import Mapping
from ridge import FilesystemCapability, ProviderContext, ResourceCapabilities
from ridge.model import ResourceProperty
class AcmeResource:
provider_name = "acme.files"
def __init__(self, name: str, filesystem: FilesystemCapability) -> None:
self.name = name
self.capabilities = ResourceCapabilities(filesystem=filesystem)
def inspect_properties(self) -> Mapping[str, ResourceProperty]:
return {}
def create_resource(
name: str,
config: Mapping[str, object],
context: ProviderContext,
) -> AcmeResource:
filesystem = build_acme_filesystem(config, context.config_dir)
return AcmeResource(name, filesystem)
The provider owns validation and construction of its configuration. Ridge
rejects provider-name collisions, identity mismatches, missing or incorrectly typed
ResourceCapabilities, a missing/non-callable inspect_properties, and construction
failures while loading the inventory, regardless of permissions. The capability
collection validates its composition and required protocol members when constructed.
Loading does not invoke inspection or prove method signatures, return values, or
backend behavior; use conformance and acceptance tests for those contracts.
ridge config validate uses this same construction path. Keep constructors
focused on configuration and defer backend interactions to capability methods;
provider code and provider-written diagnostics are not sandboxed or redacted.
The entry-point name is the YAML provider and must match the returned
resource's provider_name. Compose at most one of filesystem and storage
per resource so data requests have unambiguous addressing. Either advertises
the four data operations. Compute is optional. Transfer requires a data
capability and advertises supports_copy, not additional operation grants.
Optional delete=implementation requires one data addressing capability and
advertises data.delete. Implement DeleteCapability.delete(path, recursive=False)
returning DeleteResult, following deletion semantics.
Do not advertise deletion merely because existing write methods replace entries.
Optional data_views=implementation implements DataViewCapability:
validate_data_root(root) performs pure, nonconnecting syntax validation;
open_data_view(roots) returns narrowed data capabilities, preserving their addressing
and operation support. roots is the ordered chain of parent-relative boundaries.
Validate every physical boundary at use time, not just the final path. Ridge calls
this method lazily under the operation claim, including copy and admitted jobs.
Do not create directories as part of view resolution. Returned listings/metadata
use view-relative coordinates. Scope creation rejects narrowing when this capability
is absent. Compute, registry names, managed state and canonical claims are not rebased.
Optional footprints=implementation implements FootprintCapability:
coordinate_space()returns an immutable tuple identifying compatible canonical coordinates, orNonefor unknown mapping. Every alias in the configured lock domain must advertise the same space before Ridge narrows any operation there.plan_footprint(operation, path, roots)returns a nonempty tuple of publicFootprint(scope, mode)values, orNonefor whole-resource fallback. Include the complete immutable parent-relative root chain in canonical coordinates. The plan must cover both direct operations and corresponding transfer endpoints, including staging, publication, validation and cleanup. Mutating operations require exclusive claims. Providers cannot select another lock domain.
Both methods must be pure and nonconnecting: no mutable backend inspection,
filesystem resolution, client construction, or side effects. Ridge calls them
before admission, outside its database transaction, then rechecks scoped authority
inside admission. A scope is None or a nonempty tuple of nonempty opaque strings;
tuple ancestry, not text-prefix matching, defines overlap. Never claim narrow
coverage that depends on unprotected mutable state. Unsupported planning falls
back; malformed results fail. Oversize plans conservatively collapse to whole-domain
claims (64 claims/action, 32 components/scope, 16 KiB encoded scope).
Existing providers without this capability keep whole-resource locking.
Optional footprint_guard=implementation requires footprints and implements
FootprintGuardCapability.validate_footprint(path, roots) -> bool. Ridge calls it
only while holding the complete candidate claims, before dispatch and outside a
database transaction. It may perform read-only backend inspection, but must never
modify data or follow an unprotected alias. Return False when broader protection
is required; malformed responses fail. Broad claims need no guard. Every mutable
dependency of successful validation must remain protected until the operation ends.
Remote guards use bounded helper calls. See the built-in filesystem coverage and
fallback rules in coordination.
ridge.conformance contains reusable destructive checks for compute,
filesystem, storage, deletion, and single-file transfer implementations. Run them only
against disposable roots, prefixes, or test resources.
check_delete_capability takes an exact disposable path, a write callback,
and an existence callback. It verifies removal and repeated missing deletion;
providers must additionally test recursion, boundaries, and failure semantics.
Providers are trusted in-process Python. They execute with Ridge's ambient authority and are not sandboxed by Ridge request authorization.
Bounded reads must enforce max_bytes against content, not only prior metadata,
and raise OutputLimitExceededError rather than returning a truncated result.
See data semantics.
Transfer finish() completes staging; only commit() publishes the destination,
after both endpoints have finished successfully. Establish cleanup ownership
before accepting payload. After interruption, cancel() stops staging or reports
uncertainty; abort() must not race a possibly active writer. abort() must not delete a
previous destination retained for recovery, or undo a published result. An
unconfirmed commit must preserve available recovery artifacts rather than retrying
publication. Report the primary failure and attach secondary cleanup/recovery
details as exception notes; CLI/MCP and jobs preserve bounded diagnostic text.
See copy recovery for the built-in filesystem contract.
Built-in provider names cannot be shadowed. Providers extend implementations, not the generic operation vocabulary: they cannot redefine an operation or add CLI commands or MCP tools dynamically. New operations require a core design change. See Architecture for ownership and invariants.