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
Draft — planning seed, not an implementation ticket. It captures partial information as of 2026-08-06; a dedicated design session will produce the real spec. Do not pick this up for implementation.
What exists (verified at HEAD)
The plugin system. Formats are discovered through the visionset.formats entry-point group,
read with importlib.metadata in src/visionset/formats/registry.py — "never a hardcoded dict
and never an if fmt == "coco" chain. That is the whole plugin promise: a third-party
distribution registers into the same group and is indistinguishable from a built-in here." The
kernel structurally cannot resolve a plugin name, because import-linter forbids visionset.kernel importing visionset.formats, so ReleaseService.export takes an Exporter instance and the composition happens at the surface. Plugins are keyed by their own format_name, not by the entry-point name.
The lossiness contract (kernel/ports/exporter.py) is three declarations, each answering a
different question.
lossy: bool — a property of the format, not of a release. "A bbox-only format loses a
polygon whether or not today's dataset happens to hold one." A True costs the caller a LossyExportNotConsented once, via the allow_lossy gate word.
supported_geometries: frozenset[GeometryType] — "the checkable half of lossy", which
arrived with the export-validation work that reports excluded classes and annotations before a
run (kernel: export validation — exact report of excluded classes/annotations before running #65). It is declared over the full GeometryType rather than only the implemented subset,
so a format that will one day write masks says so once. This is what turns "this format is
lossy" into a countable report.
The principle underneath all three: declare what the format carries; refuse silent drops.
Eight shipped exporters, plus one no-op. The [project.entry-points."visionset.formats"]
table in pyproject.toml registers nine entries: yolo, coco, voc, the five lane formats
that came out of the lanes port (#223) — tusimple, curvelanes, bdd100k-lane, culane and openlane-2d, five plugins over v1's six exporter functions, since CULane's annotation file and
its segmentation mask are two artifacts of one format — and dummy, which is visionset.formats._dummy and writes nothing.
The import side is a declared port with no implementation.kernel/ports/importer.py holds a @runtime_checkable Importer Protocol — format_name plus read(src: Path) -> Iterable[Annotation] —
documented as discovered through the same entry-point group. The registry filters by port with isinstance(plugin, Exporter) precisely "because the group carries importers too". Nothing
implements it, so provenance="import" — the third of the three values in Provenance = Literal["human", "model", "import"] — currently has no producer.
Open questions (to name, not to answer here)
Candidate list and priority. Name the families here; decide nothing. Detection and
segmentation formats (COCO variants, Pascal VOC beyond what ships, CreateML, TFRecord), the
YOLO dialect spread (v5, v8, OBB, segmentation), the 3D families that follow from the 3D and
point-cloud scope issue (0.2.0 scope: 3D and point clouds #363), and whatever the video-tracking scope issue (0.2.0 scope: video tracking — object identity across frames #364) implies,
given that MOT-style formats have no home in the current model.
Import-side counterparts. Which of these formats need to read as well as write, and is that
decided per format, or is the pair the default? The scope issue for importing external datasets
(0.2.0 scope: import of external datasets #411) describes the shape of the reading half.
A public extension story in OSS. The mechanism already admits third-party distributions, but
there is no documented contract for writing one: no versioning statement on the Exporter and Importer protocols, no stability promise, and no worked example outside this repository.
Deciding whether OSS VisionSet offers that is a product call rather than a technical one.
Related open threads
The AI-assist substrate issue (#81) still carries a live Importer bullet at HEAD: "Importer
port made real (COCO/YOLO in) — the third provenance value, import, currently has no producer;
imports are also the cheapest path to pre-annotations from external models." The ModelProvider
bullets in that same issue are a separate thread and are not this milestone's concern.
Draft — planning seed, not an implementation ticket. It captures partial information as of 2026-08-06; a dedicated design session will produce the real spec. Do not pick this up for implementation.
What exists (verified at HEAD)
The plugin system. Formats are discovered through the
visionset.formatsentry-point group,read with
importlib.metadatainsrc/visionset/formats/registry.py— "never a hardcoded dictand never an
if fmt == "coco"chain. That is the whole plugin promise: a third-partydistribution registers into the same group and is indistinguishable from a built-in here." The
kernel structurally cannot resolve a plugin name, because import-linter forbids
visionset.kernelimportingvisionset.formats, soReleaseService.exporttakes anExporterinstance and the composition happens at the surface. Plugins are keyed by their own
format_name, not by the entry-point name.The lossiness contract (
kernel/ports/exporter.py) is three declarations, each answering adifferent question.
lossy: bool— a property of the format, not of a release. "A bbox-only format loses apolygon whether or not today's dataset happens to hold one." A
Truecosts the caller aLossyExportNotConsentedonce, via theallow_lossygate word.supported_geometries: frozenset[GeometryType]— "the checkable half oflossy", whicharrived with the export-validation work that reports excluded classes and annotations before a
run (kernel: export validation — exact report of excluded classes/annotations before running #65). It is declared over the full
GeometryTyperather than only the implemented subset,so a format that will one day write masks says so once. This is what turns "this format is
lossy" into a countable report.
degraded_geometries— carried, but reduced. It was added (formats: the export report says polygons are not carried while YOLO and VOC write them as bounding boxes #158) becausesupported_geometrieswas being read with two intents at once: YOLO and VOC write a polygon asits axis-aligned bounding box, which is neither "absent from the output" nor "written as it
stands", and the model had no word for it.
The principle underneath all three: declare what the format carries; refuse silent drops.
Eight shipped exporters, plus one no-op. The
[project.entry-points."visionset.formats"]table in
pyproject.tomlregisters nine entries:yolo,coco,voc, the five lane formatsthat came out of the lanes port (#223) —
tusimple,curvelanes,bdd100k-lane,culaneandopenlane-2d, five plugins over v1's six exporter functions, since CULane's annotation file andits segmentation mask are two artifacts of one format — and
dummy, which isvisionset.formats._dummyand writes nothing.The import side is a declared port with no implementation.
kernel/ports/importer.pyholds a@runtime_checkable ImporterProtocol —format_nameplusread(src: Path) -> Iterable[Annotation]—documented as discovered through the same entry-point group. The registry filters by port with
isinstance(plugin, Exporter)precisely "because the group carries importers too". Nothingimplements it, so
provenance="import"— the third of the three values inProvenance = Literal["human", "model", "import"]— currently has no producer.Open questions (to name, not to answer here)
segmentation formats (COCO variants, Pascal VOC beyond what ships, CreateML, TFRecord), the
YOLO dialect spread (v5, v8, OBB, segmentation), the 3D families that follow from the 3D and
point-cloud scope issue (0.2.0 scope: 3D and point clouds #363), and whatever the video-tracking scope issue (0.2.0 scope: video tracking — object identity across frames #364) implies,
given that MOT-style formats have no home in the current model.
decided per format, or is the pair the default? The scope issue for importing external datasets
(0.2.0 scope: import of external datasets #411) describes the shape of the reading half.
there is no documented contract for writing one: no versioning statement on the
ExporterandImporterprotocols, no stability promise, and no worked example outside this repository.Deciding whether OSS VisionSet offers that is a product call rather than a technical one.
Related open threads
The AI-assist substrate issue (#81) still carries a live Importer bullet at HEAD: "
Importerport made real (COCO/YOLO in) — the third provenance value,
import, currently has no producer;imports are also the cheapest path to pre-annotations from external models." The
ModelProviderbullets in that same issue are a separate thread and are not this milestone's concern.