LoopX Extension and Capability Registration Patterns Explained
LoopX uses a two-layer registration system where extensions declare capabilities in TOML manifests and the CapabilityRegistry validates and links providers, capability records, and implementations at runtime.
The huangruiteng/loopx repository implements a modular architecture that separates capability discovery from extension lifecycle management. This guide covers both patterns with implementation details from the source code.
What Is a Capability in LoopX?
A capability represents a concrete feature that users can interact with—such as a finance connector or data processor. Capabilities are owned by providers, which can be builtin (core LoopX) or extension (third-party). The CapabilityRegistry in loopx/capabilities/registry.py maintains three mutable tables:
providers: Logical sources that declare capabilitiesrecords: Capability definitions with metadataimplementations: Protocol bindings between capabilities and providers
Capability Registration Pattern
The capability registration pattern follows a three-step validation chain in CapabilityRegistry. Each step enforces required fields and origin/visibility rules.
Step 1: Register the Provider
A provider must contain id, origin, and four boolean state flags. In loopx/capabilities/registry.py (lines 35-68), register_provider() validates these fields before storage.
from loopx.capabilities.registry import CapabilityRegistry
registry = CapabilityRegistry()
provider = {
"id": "finance",
"origin": "extension", # or "builtin"
"declared": True,
"installed": True,
"enabled": True,
"ready": True,
}
registry.register_provider(provider)
The origin field distinguishes core LoopX functionality from third-party extensions. The ready flag indicates whether the provider's dependencies are satisfied.
Step 2: Register the Capability Record
Capability records are validated against REQUIRED_CAPABILITY_FIELDS (id, title, status, user_value, next_real_step). Public capabilities require additional fields: real_world_anchor and entry_command. See loopx/capabilities/registry.py (lines 70-106).
capability = {
"id": "finance_connector",
"title": "Finance Connector",
"status": "stable", # "stable", "beta", or "experimental"
"user_value": "connect to financial data APIs",
"next_real_step": "run", # guides the user workflow
"origin": "extension",
"visibility": "public", # "public" or "internal"
"provider_id": "finance",
"real_world_anchor": "https://finance.example.com",
"entry_command": "loopx finance connect",
}
registry.register_capability(capability)
The next_real_step field determines what action LoopX prompts the user to take after discovery. The entry_command provides a CLI entry point for public capabilities.
Step 3: Register the Implementation
Implementations bind capabilities to concrete protocols. In loopx/capabilities/registry.py (lines 114-138), register_implementation() links the capability to a provider and protocol version.
impl = {
"capability_id": "finance_connector",
"provider_id": "finance",
"protocol": "finance_extension_v0", # arbitrary protocol identifier
}
registry.register_implementation(impl)
Multiple implementations can exist for the same capability, allowing protocol versioning or alternative backends.
Extension Registration Pattern
Extensions are standalone Python packages registered through CLI commands and managed by the runtime system in loopx/extensions/runtime.py.
Scaffolding New Extensions
The scaffold_extension() function in loopx/extensions/scaffold.py (lines 84-143) generates a minimal package structure:
from loopx.extensions.scaffold import scaffold_extension
result = scaffold_extension(
"my_extension",
destination="packages/my_extension",
version="0.1.0",
execute=True, # False for dry-run preview
)
# Returns: {"status": "success", "next_commands": [...]}
The scaffold creates:
extension.toml: Manifest with provider and capability declarationspyproject.toml: Poetry-based Python package configurationsrc/: Source stub with CLI entry pointexamples/: Request/response schema samples
CLI Registration Commands
The register_extension_commands() function in loopx/cli_commands/extension.py (lines 88-152) adds sub-commands under loopx extension:
| Command | Purpose |
|---|---|
init |
Preview or create extension scaffold |
install |
Validate manifest, run doctor checks, persist state |
upgrade |
Update to new manifest version |
enable / disable |
Toggle provider enabled flag |
rollback |
Revert to prior manifest revision |
run |
Invoke standalone extension with JSON payload |
All commands support --execute for real effects; without it, they print planned actions for validation.
Runtime Handling
The extension runtime in loopx/extensions/runtime.py provides three core operations:
install_extension(): Validates manifest, updatesdefault_extension_state_file, and callsCapabilityRegistry.register_provider(),register_capability(), andregister_implementation()for each declared capabilityenable_extension()/disable_extension(): Flips provider state flagsrun_standalone_extension(): Loadssrc/<module>/cli.pyand forwards JSON request payload
These helpers are invoked from handle_extension_command() (lines 75-184).
How Extension and Capability Patterns Interact
When an extension is installed, its extension.toml drives capability registration. The [capabilities] section enumerates records, and the [provider] block defines the provider:
# Parsed from extension.toml by install_extension()
registry = CapabilityRegistry()
registry.register_provider(provider_record) # from [provider]
for cap in manifest["capabilities"]:
registry.register_capability(cap)
for impl in cap.get("implementations", []):
registry.register_implementation(impl)
Built-in capabilities follow the identical path, except with origin: "builtin" and manifests located in core LoopX packages. This uniform treatment allows LoopX to handle built-in and third-party features identically.
Complete Registration Example
from loopx.capabilities.registry import CapabilityRegistry
registry = CapabilityRegistry()
# 1. Register provider
registry.register_provider({
"id": "analytics",
"origin": "extension",
"declared": True,
"installed": True,
"enabled": True,
"ready": True,
})
# 2. Register capability
registry.register_capability({
"id": "real_time_dashboard",
"title": "Real-Time Dashboard",
"status": "stable",
"user_value": "visualize live data streams",
"next_real_step": "enable",
"origin": "extension",
"visibility": "public",
"provider_id": "analytics",
"real_world_anchor": "https://analytics.example.com",
"entry_command": "loopx analytics dashboard",
})
# 3. Register implementation
registry.register_implementation({
"capability_id": "real_time_dashboard",
"provider_id": "analytics",
"protocol": "analytics_grpc_v2",
})
# 4. Retrieve enriched record
dashboard = registry.get("real_time_dashboard")
print(dashboard["provider"]["enabled"]) # True
print(dashboard["implementations"]) # List of protocol bindings
CLI Workflow for Extension Management
# Scaffold extension (dry-run preview)
loopx extension init my_analytics --destination packages/my_analytics
# Create files on disk
loopx extension init my_analytics --destination packages/my_analytics --execute
# Install and register capabilities
loopx extension install --manifest packages/my_analytics/extension.toml --execute
# Enable if not auto-enabled
loopx extension enable my_analytics --execute
# Run with sample request
loopx extension run my_analytics --input-json packages/my_analytics/examples/request.json --execute
Key Source Files
| File | Role |
|---|---|
[loopx/capabilities/registry.py](https://github.com/huangruiteng/loopx/blob/main/loopx/capabilities/registry.py) |
Core registry with validation and linking logic |
[loopx/capabilities/catalog.py](https://github.com/huangruiteng/loopx/blob/main/loopx/capabilities/catalog.py) |
Manifest parsing for capability definitions |
[loopx/cli_commands/capability.py](https://github.com/huangruiteng/loopx/blob/main/loopx/cli_commands/capability.py) |
CLI queries (loopx capability list) |
[loopx/extensions/scaffold.py](https://github.com/huangruiteng/loopx/blob/main/loopx/extensions/scaffold.py) |
Extension package generator |
[loopx/cli_commands/extension.py](https://github.com/huangruiteng/loopx/blob/main/loopx/cli_commands/extension.py) |
Extension lifecycle CLI |
[loopx/extensions/runtime.py](https://github.com/huangruiteng/loopx/blob/main/loopx/extensions/runtime.py) |
State persistence and execution |
Summary
- Capability registration uses
CapabilityRegistrywith three validated tables: providers, records, and implementations - Extension registration combines scaffolding, CLI commands, and runtime state management in
loopx/extensions/runtime.py - Extensions declare capabilities in TOML manifests; the install flow automatically registers them with the registry
- Both
builtinandextensionorigins follow identical data models, enabling uniform handling - All registration calls occur at runtime when manifests are loaded, not at import time
Frequently Asked Questions
What is the difference between a provider and a capability in LoopX?
A provider is a logical source (builtin or extension) that can declare multiple capabilities. The provider tracks installation and enablement state, while a capability describes a concrete feature with user-facing metadata like user_value and entry_command. Multiple capabilities can share one provider.
How does LoopX validate capability manifests?
The CapabilityRegistry enforces validation in three stages. register_provider() checks required origin and state flags (lines 35-68). register_capability() validates against REQUIRED_CAPABILITY_FIELDS and enforces public capability rules (lines 70-106). register_implementation() verifies capability-provider linkage (lines 114-138).
Can I register capabilities without using the extension system?
Yes. Direct programmatic registration works by instantiating CapabilityRegistry and calling register_provider(), register_capability(), and register_implementation(). This is how built-in capabilities are registered—without an extension manifest, using origin: "builtin".
What happens when I disable an extension?
The disable_extension() runtime helper flips the provider's enabled flag to False. Capability lookups via registry.get() still return the record, but the enriched provider state shows enabled: False. The implementation bindings remain registered; only the provider state changes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →