| name | video-review-os-plugins |
| description | Write a custom provider for Video Review OS — a new transcription, diarization, copy, tagging, storyboard, or visual perception backend — and register it without forking the repo. Use when the user wants to plug in their own model, endpoint, or local runtime, asks how the provider registry works, wants to swap which AI serves a stage, or gets "unknown provider" behaviour. |
| license | MIT |
Writing a provider
Every AI-ish stage is a kind with named providers. Which one runs is a string in
config.toml, resolved through the registry in video_review_os/providers.py. No stage
names a vendor, and neither should yours.
Kinds: transcription, diarization, copy, tagging, storyboard, perception.
video-review-os providers
video-review-os providers --json
The contract
Two rules, both non-negotiable:
- Never raise out of your public method. Catch everything and return the kind's
deterministic result instead, with the failure recorded in the artifact. A provider
that throws takes down someone's overnight batch.
- Never widen the schema. Sanitize your output to the known enums before returning
it. The pipeline treats provider output as untrusted input, because it is.
Registering
Write a module with a register_providers() function:
from video_review_os import providers
from video_review_os.perception import PROVIDER_KIND, PerceptionProvider
class MyPerception(PerceptionProvider):
name = "my-perception"
def __init__(self, config):
self.config = config
def perceive(self, clips, context, config):
try:
enriched = my_model(clips)
except Exception:
return {"provider": "fallback", "status": "fallback", "clips": clips,
"errors": ["my-perception failed; used the deterministic reading."]}
return {"provider": self.name, "status": "ok", "clips": enriched}
def register_providers() -> None:
providers.register(PROVIDER_KIND, "my-perception", MyPerception,
summary="What this does", source="plugin-module")
Then either list it in config:
[plugins]
modules = ["my_studio.perception"]
…or ship it as an installed package advertising a video_review_os.providers entry point
whose value is a zero-argument callable:
[project.entry-points."video_review_os.providers"]
my-studio = "my_studio.perception:register_providers"
Select it like any builtin:
[perception]
provider = "my-perception"
Sanitizing perception output
Reuse the shipped sanitizers rather than writing your own — they are what keep an unknown
enum out of the artifact:
from video_review_os.perception import sanitize_visual, sanitize_reframe, taxonomy
visual = sanitize_visual(model_answer, clip["visual"], config.perception)
reframe = sanitize_reframe(model_answer.get("reframe"), clip["reframe"])
taxonomy(config.perception) gives the exact vocabulary a model is allowed to answer in —
send it in your prompt so the model has a chance of complying, and sanitize anyway.
Debugging
- Plugin import failures are collected, not raised:
video-review-os providers prints
them at the bottom, and providers.load_errors() returns them.
- An unknown provider name silently resolves to the kind's fallback. If your provider
"isn't running", check the spelling against
providers --json first.
- Providers load builtins first, plugins second, so a plugin can deliberately replace a
builtin name — check you have not done so by accident.