Skip to content

Conversation

@yondonfu
Copy link
Contributor

@yondonfu yondonfu commented Dec 17, 2025

Demo

2025-12-16.21-17-56.mp4

Architecture

This is inspired by the llm plugin system.

A plugin is just a Python package that uses the hook system from pluggy that will be installed into the same virtual env as Scope (there is a single virtual env). It can be installed via uv run daydream-scope install and uninstalled via uv run daydream-scope uninstall. These commands are thin wrappers around uv pip install and uv pip uninstall allowing us to just rely on typical Python package management and we inherit all the features of uv pip. We use uv pip instead of uv add or uv remove because the latter would modify the project deps, but we want plugins to be installed into the virtual env without changing the project deps.

A plugin adheres to ScopeHookSpec. At the moment, it has a single hookspec which is register_pipelines(). A plugin must implement this method and decorate it with @scope.core.hookimpl (example). The register_pipelines(0 method is responsible for registering one or more pipelines that should be available in Scope.

In addition to the install and uninstall commands we also introduce:

  • uv run daydream-scope plugins to list installed plugins
  • uv run daydream-scope pipelines to list available pipelines

These commands are all implemented using click.

The PipelineRegistry includes all built-in and plugin pipelines.

I've added a simple example of a plugin here that can be installed via:

uv run daydream-scope install git+https://github.com/yondonfu/scope-test-generator.git

22d559a also includes frontend changes to:

  • Hide Prompts box if the pipeline does not support prompts eg passthrough
  • Fixes an issue where you couldn't press the rewind button if the pipeline does not support prompts
  • Moves all the pipeline metadata that was hardcoded in the frontend into the backend as pipeline configs so that that becomes the single source of truth

Missing

  • There is no easy, streamlined path for tying model downloads with pipelines registered by a plugin. This is to be addressed separately.

Issues = "https://github.com/daydreamlive/scope/issues"

[tool.uv]
preview = true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This silences a warning from uv about extra-build-dependencies usage. I added this because I wanted the CLI output when using commands to be cleaner.

def plugins():
"""List all installed plugins."""

@suppress_init_output
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of this decorator is to suppress logs when using these commands to maintain cleaner CLI output.

print_version_info()
sys.exit(0)
from scope.core.pipelines.registry import (
PipelineRegistry, # noqa: F401 - imported for side effects (registry initialization)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PipelineRegistry registers pipelines at import time right now so this is just to avoid unused import errors/warnings while still ensuring that the pipeline registration happens on server startup.

setTransitionSteps(defaultSteps);

// Clear prompts if pipeline doesn't support them
if (pipeline.supportsPrompts === false) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit of a hack. If the pipeline does not support prompts we just set the prompt to an empty string for now so that the timeline still works, but it doesn't show any text. This felt like the minimal change to get things working without requiring a larger refactor right now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about hiding the timeline? I think that the timeline does not bring any value if you don't have prompts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm inclined to leave it for now to minimize drastic visual layout changes here and there are other things that having an indication of time progression may be useful for.

</Tooltip>
</TooltipProvider>
)}
{currentPipeline.modified && (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the modified attribute was adding any value so opted to just remove to simplify since we were moving a bunch of attributes to the backend.

Copy link
Collaborator

@leszko leszko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @yondonfu — this will significantly improve Scope’s extensibility for both us and the community 🚀

Thoughts / suggestions (ordered by priority):

  1. Non-GPU support
    This currently doesn’t work on non-GPU setups. I added an inline comment with suggested fix(es).

  2. Separate dependencies per pipeline
    We should consider running each pipeline in a separate process (similar to what I started in #173). This would allow each pipeline to have its own dependency set and completely avoid dependency conflicts.
    This would be a killer feature - e.g., work like @BuffMcBigHuge’s “PersonaLive!” seems largely about resolving dependency clashes. Isolating pipelines would dramatically speed up adding new ones and aligns with where we want to go anyway.

  3. Model downloads inside pipelines
    Since you already mentioned this: it might be a good time to move model downloading into the pipeline itself. A pipeline plugin without model management feels incomplete and less useful in practice.

  4. Existing pipelines as plugins
    What do you think about migrating our existing pipelines to plugins as well? They could be preinstalled, but this would give us consistent behavior across all pipelines and allow users to uninstall default ones if desired.

  5. Plugins vs. pipelines
    Do we need both concepts? Perhaps we could simplify by having a single concept (e.g., “plugins”), with each plugin containing exactly one pipeline. No strong opinion - just something to consider.

setTransitionSteps(defaultSteps);

// Clear prompts if pipeline doesn't support them
if (pipeline.supportsPrompts === false) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about hiding the timeline? I think that the timeline does not bring any value if you don't have prompts.

"""Hook specifications for Scope plugins."""

@hookspec
def register_pipelines(self, register):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to force people to annotate @scope.core.hookimpl in their plugins? Maybe we should just not annotate anything, just when someone installs a plugin, then look into their code and import everything that implements our Pipeline interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is required for using pluggy which relies on the decorator for detecting the hook impl. I'm inclined to just start with that unless we feel like we have a strong reason to start handrolling something ourselves. But, we can always make improvements on this if we need to.

@yondonfu
Copy link
Contributor Author

A couple additional changes:

7654e86 moves heavy model related imports into init for built-in pipelines. I found this to be the simplest way to avoid triggering those imports when the pipelines are registered - those imports can be a bit slow so better to trigger them as lazily as possible.

6ab629f I noticed a frontend bug where I couldn't change the Input mode after switching to a pipeline. I think the logic flaw was that whenever the input mode changed it would check if the input mode was different than the default and then set the default. I'm not sure when this bug was introduced, but figured would push a quick fix.

@yondonfu
Copy link
Contributor Author

yondonfu commented Dec 18, 2025

@leszko

Non-GPU support

Addressed.

Separate dependencies per pipeline

I'm leaning towards starting off with shared venv.

A few concerns I have about separate venvs per plugin:

  1. Will prematurely introduce complexity quickly before we've even begun working with folks to start developing plugins. It already requires some form of IPC. And when we do pipeline composition across plugins we would need something like CUDA IPC to keep data in VRAM (exiting just to move to the other pipeline would be bad for throughput/latency).
  2. It requires more more scaffolding to provide a good UX/DX because testing the plugin with Scope is no longer just a matter of running it like a normal Python package.

I know that dep conflicts are a challenge. However, we should consider:

  1. uv can take care of a lot dep resolution and any issues with broken venvs could be prevented with an additional dependency conflict check [1].
  2. Given 1, if there is clear guidance for plugin devs to use version ranges when possible uv can take care of finding the appropriate versions. Many headaches here are caused if the plugin pins a specific version leaving little room for the package management to resolve against other dep declarations.
  3. The most popular ML deps like torch generally have good policies around backwards compat so it should be relatively rare for a small difference in version to lead to major breakage. This can still happen, but the point is that it is not the default common case.

I suspect many issues can be addressed with the above. And there will remain some that cannot and the plugin devs will just need to fix their deps. My instinct is that that number is not large enough to justify immediately taking on the complexity of separate venvs per plugin. This doesn't preclude adding that as an option later.

[1] I think one of (not the only) reasons that handling deps for plugins is a pain is they are incremental installs (eg using uv pip install) into the same shared venv. As a result, you can end up in a situation where you install plugin A (eg package) and then plugin B but end up with a dep version that works with B but not with A. But, it is possible (with a reasonable # of LOC) to detect this incompatibility if you aggregate plugins as they are installed and before finalizing an install you can use uv sync or uv pip compile to make sure that all the plugins + deps are compatible with the deps in the project. This doesn't make dep conflicts go away, but it does avoid broken deps by detecting conflicts early.

Model downloads inside pipelines

I'll treat that as something to be addressed next (probably outside of this PR) and want to decide on the shared venv vs separate venv first and test on that.

Existing pipelines as plugins

I'm inclined to address this later and focus on plugin UX/DX first.

Plugins vs. pipelines

I see them as distinct concepts. A plugin can register one or many pipelines and this design leaves room for it introducing other extensions.

@yondonfu yondonfu marked this pull request as draft December 21, 2025 22:26
yondonfu and others added 11 commits December 22, 2025 10:43
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
…for prompts box

Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Rafał Leszko <rafal@livepeer.org>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Signed-off-by: Yondon Fu <yondon.fu@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants