You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The standing invariant — zero orphaned capabilities, none declared without a surface that
renders it — is what closes the capability vocabulary. If plugins could add capabilities, every
installed plugin would create orphans by definition. Closing capabilities is also what lets a
single generic dashboard — the Inference screen organized by what a connection enables (#499) —
render any provider without plugins shipping frontend code.
So: closed capabilities, open providers.ModelCapability
(src/visionset/kernel/domain/inference.py) grows only by a deliberate kernel change shipped
alongside the surface that consumes it. What a plugin adds is a driver for a capability the
application already defines.
The provider contract (to be designed here)
A provider must be able to:
identify itself and the contract version it targets;
declare the families it serves and its curated entries (pinned revisions, sizes);
price a download for an exact snapshot;
fetch weights into the content-addressed cache;
run predictions over domain types for the capabilities it maps to;
Capability mapping is derived from declared families through the same mechanism src/visionset/inference/families.py uses today: CAPABILITY_BY_FAMILY is built from SEGMENTER_FAMILIES and DETECTOR_FAMILIES with dict.fromkeys, never written out a second
time, so adding a family and declaring its capability are one edit. A provider never hand-writes
its capability map; the change that made connections declare what their model can be asked for
(#486) proves that derivation with a mutation test.
Layering
ModelProvider (src/visionset/kernel/ports/model_provider.py) stays a pure kernel port.
Provider authors get a toolkit layer above it — working name visionset.inference.sdk — offering
the kernel's device and precision rules (precisions_for), cache access
(src/visionset/inference/cache.py), the digest discipline in src/visionset/inference/integrity.py that came with the weights integrity check (#475),
integration with the download job that reports its bytes (#493), and refusal prose helpers.
The layer carries an explicit contract version. The contract is experimental until
declared stable in a later release: everything is free before first publication and breaking
after. That is the same lesson taught by the suggest route's detail field, which was accepted,
published and then ignored (#463) — applied deliberately this time.
Discovery
An entry-point group, mirroring the exporter precedent: pyproject.toml already registers nine
exporters under [project.entry-points."visionset.formats"].
The group name is an open naming decision (candidate: visionset.providers) — flagged deferred-needs-input on this issue, to be decided before the first implementation PR that
registers one.
Degradation and trust
A connection whose provider is not installed does not break and is not deleted: it renders
with prose naming the missing provider and coherent allowed_actions — the missing-format
treatment. Documentation states plainly that installing a plugin is trusting its author with code
execution in the workers, exactly as any pip package.
0.1.0 scope vs. later
In 0.1.0: the contract exists internally; both shipped adapters — src/visionset/inference/sam_provider.py (point-prompted, SAM 2 family) and src/visionset/inference/transformers_provider.py (text-prompted, Grounding DINO family),
resolved by provider_for in src/visionset/inference/providers.py — are migrated to consume it;
the discovery mechanism works for in-tree providers; nothing is documented as a public API.
Later (its own release, its own decision): contract declared stable, public docs, external
plugin support announced.
The contract is not published as a public extension API in 0.1.0, but the shipped local adapters
must run on it — the contract is proven by our own drivers before any publication. Plugins are backend driver + declarative metadata only; plugin-supplied UI is out of scope. Nothing here
touches the http connection type or precludes hosted execution.
Why this shape
The standing invariant — zero orphaned capabilities, none declared without a surface that
renders it — is what closes the capability vocabulary. If plugins could add capabilities, every
installed plugin would create orphans by definition. Closing capabilities is also what lets a
single generic dashboard — the Inference screen organized by what a connection enables (#499) —
render any provider without plugins shipping frontend code.
So: closed capabilities, open providers.
ModelCapability(
src/visionset/kernel/domain/inference.py) grows only by a deliberate kernel change shippedalongside the surface that consumes it. What a plugin adds is a driver for a capability the
application already defines.
The provider contract (to be designed here)
A provider must be able to:
sam2_videowas recognised as a point-prompt model and an unknown type made to refuse (fix(inference): sam2_video is a point-prompt model, and an unknown type refuses #458):never guess, and name what is supported.
Capability mapping is derived from declared families through the same mechanism
src/visionset/inference/families.pyuses today:CAPABILITY_BY_FAMILYis built fromSEGMENTER_FAMILIESandDETECTOR_FAMILIESwithdict.fromkeys, never written out a secondtime, so adding a family and declaring its capability are one edit. A provider never hand-writes
its capability map; the change that made connections declare what their model can be asked for
(#486) proves that derivation with a mutation test.
Layering
ModelProvider(src/visionset/kernel/ports/model_provider.py) stays a pure kernel port.Provider authors get a toolkit layer above it — working name
visionset.inference.sdk— offeringthe kernel's device and precision rules (
precisions_for), cache access(
src/visionset/inference/cache.py), the digest discipline insrc/visionset/inference/integrity.pythat came with the weights integrity check (#475),integration with the download job that reports its bytes (#493), and refusal prose helpers.
The layer carries an explicit contract version. The contract is experimental until
declared stable in a later release: everything is free before first publication and breaking
after. That is the same lesson taught by the suggest route's
detailfield, which was accepted,published and then ignored (#463) — applied deliberately this time.
Discovery
An entry-point group, mirroring the exporter precedent:
pyproject.tomlalready registers nineexporters under
[project.entry-points."visionset.formats"].The group name is an open naming decision (candidate:
visionset.providers) — flaggeddeferred-needs-inputon this issue, to be decided before the first implementation PR thatregisters one.
Degradation and trust
A connection whose provider is not installed does not break and is not deleted: it renders
with prose naming the missing provider and coherent
allowed_actions— the missing-formattreatment. Documentation states plainly that installing a plugin is trusting its author with code
execution in the workers, exactly as any pip package.
0.1.0 scope vs. later
In 0.1.0: the contract exists internally; both shipped adapters —
src/visionset/inference/sam_provider.py(point-prompted, SAM 2 family) andsrc/visionset/inference/transformers_provider.py(text-prompted, Grounding DINO family),resolved by
provider_forinsrc/visionset/inference/providers.py— are migrated to consume it;the discovery mechanism works for in-tree providers; nothing is documented as a public API.
Later (its own release, its own decision): contract declared stable, public docs, external
plugin support announced.
The contract is not published as a public extension API in 0.1.0, but the shipped local adapters
must run on it — the contract is proven by our own drivers before any publication. Plugins are
backend driver + declarative metadata only; plugin-supplied UI is out of scope. Nothing here
touches the
httpconnection type or precludes hosted execution.Sub-decisions this epic must produce
Each recorded on this issue before its slice:
deferred-needs-input).frontend/ui-core/src/screens/inferenceCatalog.tsand the grouped model select that shippedwith the curated model list and download lifecycle (feat(inference): curated model list, closed device and precision fields, download lifecycle #470).
subjects.