Capabilities
Overview
Capabilities provide application-specific services to framework components and hooks.
The framework depends on capability contracts rather than concrete implementations. This allows applications to integrate databases, metadata registries, relation lookup services and other infrastructure without creating hard dependencies inside the framework.
Application
|
v
Capability
|
v
Framework
Capabilities form the primary extension mechanism of teksi_hooks.
Purpose
Capabilities are used when framework components require information or behaviour that depends on the hosting application.
Typical examples include:
Metadata lookup
Relationship lookup
Persistence services
External system integration
Runtime configuration access
The framework itself does not know how these services are implemented.
Capability Contracts
Capabilities define what functionality is available rather than how it is implemented.
For example:
class MetadataCapability(
Protocol,
):
def class_metadata(
self,
class_id: str,
) -> ClassMetadata:
...
Framework components depend on the capability contract while the application provides the concrete implementation.
Providing Capabilities
Applications register capability implementations through the
HookContext.
context = HookContext(
parameters={},
logger=logger,
capabilities={
MetadataCapability: metadata_capability,
},
)
Hooks and services can then request the capability they need.
Accessing Capabilities
Capabilities are retrieved from the runtime context.
metadata = context.capability(
MetadataCapability,
)
The framework validates capability requirements before hook execution.
Required Capabilities
Hooks can explicitly declare required capabilities.
class Hook(HookBase):
required_capabilities = frozenset(
{
MetadataCapability,
},
)
The hook handler verifies that all required capabilities are available before execution begins.
When to Use a Capability
A capability is appropriate when functionality depends on application-specific data or infrastructure.
Examples:
Looking up class metadata
Resolving relationships
Reading external configuration
Persisting data
Accessing a database
Integrating external services
These concerns belong outside the framework core because they vary between applications.
When Not to Use a Capability
Capabilities should not be used for functionality that can be represented as a pure model, parser, resolver or evaluator.
Examples:
Value objects
Data models
Configuration definitions
Validation findings
Pure business logic
Stateless helper functions
Keeping these concerns outside capabilities helps maintain clear architectural boundaries.
Design Principles
Capabilities in teksi_hooks follow several principles:
Depend on contracts, not implementations.
Keep infrastructure concerns outside the framework core.
Make dependencies explicit.
Avoid global state.
Support application-specific extensions.
Remain independent of business domains.
This approach allows the framework to remain lightweight while supporting a wide range of applications and deployment environments.