Skip to content

feat(models): support extension-scoped shared weight groups #343

Description

@DrHepa

Summary

Add an opt-in manifest contract that allows multiple model nodes inside the same extension to reuse one or more shared weight groups while retaining their own node-specific weights.

The first phase should be strictly extension-scoped. Sharing weights between unrelated extensions can be designed later once the local ownership, runtime, download, readiness, and deletion semantics are stable.

Problem

Modly currently treats each model capability as both:

  1. a capability identity: "/"
  2. a physical weight owner: "//"

This works for single-node extensions, but a multi-node extension downloads another copy of the same checkpoint for every node, even when those nodes use the same underlying model.

The recently added "model_sources" contract supports multiple Hugging Face repositories per node, but every source is still confined to that node's model directory.

This causes substantial duplication in real extensions:

  • SenseNova Vision 7B MoT
    • The extension exposes 15 model nodes.
    • Every node uses the same "sensenova/SenseNova-Vision-7B-MoT" checkpoint and repeats the same download plan.
    • The checkpoint is approximately 29.6 GB.
    • Installing all 15 capabilities can therefore occupy approximately 444 GB instead of one 29.6 GB copy.
  • DreamStyle3D
    • "trellis-image-large" and "dreamstyle3d" both need common TRELLIS and DINOv2 files.
    • Approximately 2.85 GB of checkpoint data is currently duplicated.
    • The DreamStyle node also needs private DreamStyle and CLIP weights, so redirecting the entire node directory to another node is not sufficient.
  • Pixal3D and a possible WorldSculpt node
    • WorldSculpt uses Pixal3D as its pretrained base and adds its own multi-view conditioning and LoRA/adaptation weights.
    • The official installation downloads both "TencentARC/Pixal3D" and "AlayaLab/WorldSculpt".
    • A WorldSculpt capability inside the Pixal3D extension should reuse the existing Pixal3D weights and download only the additional WorldSculpt assets.

Proposed solution

Introduce extension-scoped shared weight groups.

A shared group owns a validated "model_sources" plan once. Nodes reference the groups they require and may continue declaring private "model_sources".

Possible manifest shape:

{
"id": "pixal3d",
"type": "model",

"weight_groups": [
{
"id": "pixal3d-base",
"model_sources": [
{
"id": "pixal3d",
"provider": "huggingface",
"repo_id": "TencentARC/Pixal3D",
"revision": "",
"destination": ".",
"checks": [
"pipeline.json"
]
}
]
}
],

"nodes": [
{
"id": "generate",
"weight_groups": [
"pixal3d-base"
]
},
{
"id": "worldsculpt",
"weight_groups": [
"pixal3d-base"
],
"model_sources": [
{
"id": "worldsculpt-adapter",
"provider": "huggingface",
"repo_id": "AlayaLab/WorldSculpt",
"revision": "",
"destination": "worldsculpt",
"checks": [
"worldsculpt/"
]
}
]
}
]
}

The exact field names are open to adjustment, but shared and node-private sources need separate ownership and storage roots.

Storage contract

Suggested layout:

/
/
_shared/
/
...
/
...

Rules:

  • Shared group sources are stored under "_shared/".
  • Node-specific sources remain under "".
  • Group IDs are local to their extension.
  • Group IDs, destinations, and checks use the same portable-ID and path-confinement rules as "model_sources".
  • Absolute paths, "..", symlink escapes, separators inside IDs, and cross-extension references are rejected.
  • No symlinks or hard links are required.
  • "_shared" should be reserved and rejected as a node ID.

Download behavior

Installing a node should build one effective plan from:

  1. all referenced shared weight groups;
  2. the node's private "model_sources".

Expected behavior:

  • A completed shared group is not downloaded again for another node.
  • "Install all" deduplicates shared groups before starting downloads.
  • Concurrent node installations cannot write to the same shared group simultaneously.
  • Active download locking is based on the canonical physical target, not only the requesting node ID.
  • Pause, resume, cancel, repair, progress, revision pinning, filters, and checks continue to use the existing "model_sources" behavior.
  • Failure of a node-private source does not mark the shared group as incomplete.
  • Partially downloaded shared data remains recoverable through the existing resume/repair flow.

Readiness behavior

A node is ready only when:

  • every referenced shared group passes all its checks; and
  • every node-private source passes all its checks.

This allows the following states:

  • Pixal3D base downloaded → the regular Pixal3D node is ready.
  • Pixal3D base downloaded but WorldSculpt weights missing → the WorldSculpt node is not ready.
  • Installing WorldSculpt downloads only its missing private sources.
  • One SenseNova shared group downloaded → all SenseNova capability nodes that have no private sources become ready.

The Models UI should make this relationship visible, for example:

Pixal3D base weights Shared · Installed
Image to 3D Ready
WorldSculpt Additional weights required

Runtime contract

Capability identity must remain separate from storage identity.

"MODEL_DIR.name" must not be used as the only way to determine which node is running. That assumption fails as soon as multiple nodes share a directory.

The runtime should receive explicit information equivalent to:

MODEL_ID=/
MODEL_NODE_ID=
MODEL_DIR=
SHARED_MODEL_DIRS={"pixal3d-base":""}

The exact transport may be environment variables or a typed runtime context, but it must work for both direct and subprocess extensions.

Requirements:

  • The selected generator remains "/".
  • "MODEL_DIR" retains its existing node-private meaning for backward compatibility.
  • Shared group paths are supplied explicitly by the host.
  • Extensions do not construct shared paths from user-controlled strings.
  • Updating model storage paths at runtime updates both private and shared directories.

Deletion and uninstall behavior

Shared weights must not be deleted as if they belonged to one capability.

Expected behavior:

  • Removing a node's private weights deletes only that node's private directory.
  • Removing a shared group requires a separate, explicit action and warns that every dependent node will become unavailable.
  • All loaded generators that reference a group are unloaded before that group is removed.
  • Uninstalling an extension with “delete model weights” selected removes the extension's model root once, including shared and private data.
  • Deleting one capability must never silently remove a group still required by sibling capabilities.
  • UI state is refreshed for every affected node after a shared group is downloaded, repaired, cancelled, or removed.

Manifest validation

Reject the extension during validation when:

  • a node references an unknown group;
  • group IDs are duplicated;
  • a group ID or destination is unsafe;
  • a group contains invalid or colliding sources;
  • checks escape their group root;
  • a node attempts to reference a group from another extension;
  • shared-weight metadata is declared on a non-model extension in this first phase.

The Python and Electron implementations should apply equivalent normalization and validation rules.

Backward compatibility

  • Existing manifests without "weight_groups" keep their current behavior.
  • Legacy "hf_repo" and "download_check" fields continue to normalize as node-owned sources.
  • Existing node-level "model_sources" remain private to that node.
  • Existing model directory layouts remain valid.
  • Extensions opt into shared storage explicitly.
  • No automatic migration or filesystem deduplication of already downloaded legacy copies is required in the first phase.
  • Existing model, workflow, pause/resume/cancel, and uninstall behavior must remain unchanged for manifests that do not use shared groups.

Extension authors can provide migration guidance when changing an existing extension to the shared layout. Safe automatic migration of existing duplicate files can be considered separately.

Acceptance criteria

  • A manifest can declare one or more extension-scoped shared weight groups.
  • Multiple sibling model nodes can reference the same group.
  • A node can combine shared groups with private "model_sources".
  • Installing two nodes that reference the same group downloads that group only once.
  • "Install all" deduplicates shared download work.
  • Readiness is calculated from all shared and private checks required by each node.
  • Runtime node selection does not depend on the shared directory name.
  • Direct and subprocess extensions receive the resolved shared directories.
  • Removing node-private weights preserves shared groups.
  • Removing a shared group warns about and invalidates all dependent nodes.
  • Unsafe, unknown, duplicate, or cross-extension group references are rejected.
  • Existing manifests and node-owned weight directories behave exactly as before.

Suggested regression fixtures

Fully shared checkpoint

Two or more nodes reference one group and have no private sources.

Verify:

  • one physical download;
  • all nodes become ready;
  • concurrent installation cannot start duplicate writes;
  • removing the group invalidates all nodes.

This represents the SenseNova use case.

Shared base plus private adapter

Two nodes reference the same base group. One node declares an additional private adapter source.

Verify:

  • downloading the base node does not download the adapter;
  • the adapter node remains unavailable until its private source is complete;
  • installing the adapter node reuses the base;
  • deleting the adapter source preserves the base node.

This represents DreamStyle3D and Pixal3D/WorldSculpt.

Legacy manifest

A node uses only "hf_repo", "download_check", or node-level "model_sources".

Verify that download, readiness, runtime paths, deletion, and UI state are unchanged.

Out of scope for phase 1

  • Sharing groups between different extensions.
  • A global or content-addressed model cache.
  • Automatic deduplication or migration of existing files.
  • Sharing Python environments, extension source code, or processes.
  • Arbitrary local filesystem paths.
  • Non-Hugging-Face providers.
  • Changes to the model execution API unrelated to resolved weight paths.

A later phase could introduce cross-extension sharing through a separately reviewed global identity, versioning, trust, reference-counting, and garbage-collection contract.

Related work

A direct node-owner alias is not sufficient for this issue because it cannot cleanly represent a shared base plus node-private adapters, and it risks coupling runtime node selection and deletion to a filesystem path.

Checklist

  • Existing requests and pull requests were reviewed.
  • The first phase is limited to sibling model nodes inside one extension.
  • Backward compatibility and filesystem confinement are required.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions