Source extensions
Source extensions
Retro extension API 1 supports installable source adapters. A source adapter
owns host-specific discovery, raw capture, and normalization. Retro core owns
artifact paths, staged publication, locking, downstream processing, and the
CLI.
Inspect providers
retro extensions list
retro extensions doctor
list reads entry-point metadata without importing optional packages.
doctor loads each provider and verifies:
- the package declares a supported
RETRO_EXTENSION_API; - the entry-point name matches the provider’s validated host ID;
- the provider has a display name,
discover(), andimport_session(); - no built-in or installed package claims the same host name.
One broken extension does not prevent unrelated providers from loading. Collisions fail closed instead of choosing a package by installation order.
Install the OpenCode reference adapter
The repository includes a fixture-backed reference package:
python -m pip install -e "./adapters/retro-opencode"
retro extensions doctor
Set OPENCODE_HOME when the source is not under ~/.opencode:
export OPENCODE_HOME=/path/to/opencode-home
retro list --host opencode
retro import opencode --latest
See the adapter’s COMPATIBILITY.md for supported layouts and known gaps.
Implement a provider
An adapter class accepts a retro.sdk.Layout and implements the public source
protocol:
from retro.sdk import ImportResult, Layout, SessionDescriptor
RETRO_EXTENSION_API = "1"
class ExampleSource:
host = "example"
display_name = "Example Agent"
def __init__(self, layout: Layout):
self.layout = layout
def discover(self) -> list[SessionDescriptor]:
...
def import_session(
self,
*,
identifier: str,
force: bool = False,
) -> ImportResult:
...
Register it in the package’s pyproject.toml:
[project.entry-points."retro.sources"]
example = "example_retro:ExampleSource"
Host IDs must match ^[a-z][a-z0-9-]*$. Session IDs must be path-safe. The
entry-point name and ExampleSource.host must match.
Publication contract
The provider receives a staging Layout, not the live archive layout. It must:
- Copy source evidence into
layout.raw_dir(host, session_id). - Preserve unsupported records as
event_type=\"unknown\". - Write
NormalizedEventrows tolayout.normalized_path(host, session_id). - Return those exact paths in
ImportResult. - Use artifact-relative
RawRef.pathvalues such asraw/example/<session-id>/session.jsonl. - Refuse an unchanged existing capture unless
force=True.
Retro validates the returned host, session, and paths. It then atomically replaces the public raw directory and normalized JSONL as one managed publication operation. If capture or normalization fails, the existing public artifacts remain unchanged.
Provider code must not write signals, mined memories, dashboards, global configuration, or files outside the supplied layout.
Compatibility
The API version is independent from the retro-ai package version. Providers
should constrain the core release range they test, for example:
dependencies = ["retro-ai>=0.4.0,<0.6"]
Retro supports Python 3.9 and newer. Extension annotations should use
from __future__ import annotations when using modern union syntax.