* docs: centralize daemon data directory contract * fix(e2e): allow slower artifact consistency navigation Generated-By: looper 0.9.5 (runner=fixer, agent=codex) * docs: localize daemon data directory pointers Generated-By: looper 0.9.5 (runner=fixer, agent=codex) --------- Co-authored-by: Looper <looper@noreply.github.com>
30 KiB
Open Design Plugin Registry — Plan (living)
One sentence: Turn the existing
open-design-marketplace.jsonfederation into a real npm-/clawhub-/skills.sh-style registry: GitHub repo as the v1 storage backend,odCLI as the canonical client, official site as one rendered consumer, and the whole thing pluggable so a third party can stand up their own Open Design plugin source with one config line.
Source spec: docs/plugins-spec.md · zh-CN
docs/plugins-spec.zh-CN.md.
Sibling plan: plugins-implementation.md —
that file owns the per-plugin runtime/apply/snapshot pipeline. This file
owns the registry / distribution / website / multi-source story.
References (shape, not API):
- Clawhub — agent-era plugin catalog with GitHub-PR submission and a single rendered index site.
- skills.sh — community skill registry with
id:vendor/nameaddressing and copy-to-clipboard install commands. - npm registry — versioned packages, scoped names, publish/yank lifecycle, lockfiles, integrity hashes.
0. Invariants (lock first; never violate without a spec patch)
- R1. CLI is the canonical client. Every UI action and every website
feature must be expressible as one
odsubcommand. UI / site are renderers. - R2. Storage backend is swappable. GitHub repo is the v1 backend, but
daemon code talks to a
RegistryBackendinterface. Replacing GitHub with a managed DB later must be a one-file swap, not a refactor. - R3.
SKILL.mdfloor stays portable. A plugin published to OD's registry must still install cleanly as a plain agent skill in Claude Code / Cursor / Codex / Gemini CLI / OpenClaw / Hermes.open-design.jsonremains an additive sidecar (per spec §1). - R4. Trust vocabulary is one set, everywhere. Contracts, daemon, CLI,
UI, and website all use
official/trusted/restricted. (Todaymarketplace.tsshipsofficial|trusted|untrustedand the runtime shipsbundled|trusted|restricted— P0 unifies these and normalizes legacyuntrustedrows torestricted.) - R5. Federation is the default, not the exception. OD's own registry is one source among many. Adding a third-party registry URL is symmetric to adding ours; no special-casing in code paths.
- R6. Provenance is preserved end-to-end. Every installed plugin
carries
sourceMarketplaceId+marketplaceTrust+ resolved transport (github/url/local/bundled), so UI and audit can answer "where did this come from?" without re-resolving.
1. Target architecture
1.0 Product surface map
The registry architecture has three stable layers:
Registry supply network
GitHub repo in v1, database backend later.
Owns package identity, versions, trust, integrity, yanking, provenance.
od CLI
Canonical client and automation API.
Owns login/whoami, publish, pack, doctor, search, install, upgrade.
Product UI
Human operating console.
Owns fast use, discovery, source management, provenance/risk display.
Concrete relationship:
Plugin source repo
open-design.json includes plugin.repo
|
| od plugin validate / pack / publish
v
Plugin artifact
GitHub ref, GitHub Release .tgz, HTTPS archive, or local folder
|
v
Registry index
v1: open-design/plugin-registry or this repo
community/**/open-design.json
generated open-design-marketplace.json
future: DatabaseRegistryBackend
|
| od marketplace search / od plugin install
v
Installed plugin
local runnable record with sourceMarketplaceId, trust, integrity, resolved ref
Product surface semantics:
- Home / Official starters is not a separate registry. It is a curated
shortcut shelf for already-installed bundled/official workflows so users can
immediately click
Use. Bundled official plugins are the preinstalled cache of theofficialregistry source, not a separate distribution model. - Plugins / Installed is the full local runnable inventory: bundled official plugins, user-created plugins, direct GitHub/URL/local installs, and marketplace-installed plugins.
- Plugins / Available is the registry discovery layer: entries from configured Sources that are not installed yet or have upgrades available.
- Plugins / Sources is the registry source manager: official, community, self-hosted, and enterprise catalogs; trust tier; refresh; remove; auth/cache status later.
- Plugins / Team is the enterprise governance layer: private catalogs, organization allowlists, approvals, audit, and policy.
- open-design.ai/plugins is the public renderer of the official and community registry sources, not a separate source of truth.
Agent consumption boundary:
User-added registry
Sources -> Available -> Install -> Installed -> agent context/runtime
Packaged official plugins
official registry -> bundled preinstall cache -> Installed/bundled
-> Home Official starters -> agent
Default community registry
community source -> Available by default -> user installs intentionally
-> installed plugin record -> Installed -> agent
Available is not directly consumable by the agent. It is a supply pool. The
agent consumes the installed set: bundled official plugins, user-created
plugins, direct GitHub/URL/local installs, and marketplace-installed plugins. A
future "Use from Available" convenience action may auto-install first, but it
must still create an installed record before execution.
User-created and user-installed plugins are persisted through daemon-managed
storage. This plan MUST NOT define daemon data paths; read the root
AGENTS.md section Daemon data directory contract before changing or
documenting plugin storage. Daemon startup reloads installed records from
SQLite and resolves those user-state plugin folders; a packaged runtime upgrade
should not overwrite them. Bundled official plugins stay inside the runtime
image and are re-registered on boot as official-source preinstalls.
Authoring and publishing mirror the consumption loop:
Create plugin
-> agent-assisted authoring
-> od plugin scaffold / validate / local install / pack
-> od plugin login/whoami through gh
-> od plugin publish
-> GitHub registry PR
-> generated open-design-marketplace.json
-> Available for downstream users after refresh
The Create plugin button should therefore launch an agent workflow that helps
the user describe the plugin, writes SKILL.md and open-design.json, adds
examples/preview metadata, validates locally, installs a test copy, packs it,
and then drives the GitHub-backed publish PR. The CLI remains canonical; the
agent is the product wrapper around the CLI workflow.
v1 registry scope is intentionally simple: a GitHub repo with reviewable source
entries plus a generated open-design-marketplace.json. The JSON is what
daemon/CLI/UI fetch; the source entries are what humans review in PRs. This can
start in the main Open Design repo, but the code path must still be expressed as
RegistryBackend so moving to open-design/plugin-registry or a database later
does not change the product model.
1.1 Storage abstraction
packages/registry-protocol/ ← NEW pure TS, schema + interface
├── backend.ts ← RegistryBackend interface
├── types.ts ← RegistryEntry, RegistryVersion,
│ PublishRequest, SearchResult, …
└── tests/
apps/daemon/src/registry/ ← side-effect zone
├── github-backend.ts ← v1: PR-based publish, raw.git read
├── http-backend.ts ← already-exists shape (marketplace.json)
├── local-backend.ts ← dev/test fixture
├── cache.ts ← on-disk cache + ETag refresh
├── lockfile.ts ← od-plugin-lock.json writer/reader
└── publish.ts ← orchestrates pack → fork → PR
RegistryBackend (sketch — exact shape lands in P0):
interface RegistryBackend {
id: string; // e.g. "official" | "acme-private"
kind: 'github' | 'http' | 'local' | 'db';
trust: MarketplaceTrust;
// read
list(filter?: ListFilter): Promise<RegistryEntry[]>;
search(q: string): Promise<SearchResult[]>;
resolve(name: string, range?: string): Promise<ResolvedEntry>;
manifest(name: string, version: string): Promise<PluginManifest>;
// write (optional — http/db may be read-only from CLI perspective)
publish?(req: PublishRequest): Promise<PublishOutcome>;
yank?(name: string, version: string, reason: string): Promise<void>;
// health
doctor(): Promise<DoctorReport>;
}
1.2 GitHub-backed v1 layout
A dedicated public repo — proposed open-design/plugin-registry — owns the
canonical official catalog. Third parties fork the same shape and point their
own marketplace.json URL at it.
open-design/plugin-registry/
├── plugins/
│ └── <vendor>/<plugin-name>/
│ ├── manifest.json ← latest copy of open-design.json
│ ├── versions/
│ │ ├── 0.1.0.json ← frozen manifest snapshot per version
│ │ └── 0.2.0.json
│ ├── README.md ← rendered on the website
│ ├── OWNERS ← GitHub usernames with publish rights
│ └── tarball.txt ← canonical archive URL (GitHub release)
├── marketplace.json ← generated index; what daemons fetch
├── schema/
│ └── open-design.marketplace.v1.json
├── .github/workflows/
│ ├── validate-pr.yml ← schema + manifest + license + a11y
│ └── publish-index.yml ← rebuild + commit marketplace.json
└── docs/ ← "how to publish" guide
Why a separate repo: keeps the main monorepo green, gives publishers a clear contribution target, lets us mirror the same shape for third-party registries verbatim.
Tarball storage: plugins ship as .tgz (per existing od plugin pack).
v1 uses GitHub Releases of the plugin's own source repo as the canonical
archive host; the registry only stores a URL + integrity hash, never the bytes.
This keeps the registry repo small and makes the storage layer trivially
swappable.
Namespace policy: published package ids are always vendor/plugin-name.
The vendor is the GitHub org/user or enterprise org namespace. The full id is
stable after publish; rename means new id plus alias/deprecation metadata.
Source repo policy: accept "anything that packs". The source repo does not
need a special layout if od plugin validate and od plugin pack pass. The
manifest must include plugin.repo in open-design.json, pointing to the
canonical source repository or subdirectory.
Tarball fallback: GitHub Releases are the default archive host, but raw HTTPS/object-storage archive URLs are accepted when Releases are unavailable. Fallback archives require integrity hashes.
1.3 Publish flow (PR-based)
od plugin publish end-to-end:
- Run
od plugin pack→ produces<vendor>-<name>-<version>.tgz+ manifest digest. - Read or create a GitHub release on the plugin's own source repo, upload the tarball, capture release asset URL + SHA-256.
gh auth statusto confirm login (no token persisted byod).- Fork (or reuse fork of)
open-design/plugin-registryviagh repo fork. - Check out a branch
publish/<vendor>-<name>-<version>. - Write/refresh
plugins/<vendor>/<name>/manifest.jsonandversions/<version>.json, append entry to a per-plugin index, runpnpm run validatelocally. gh pr createwith a templated body containing manifest summary, capability/permission list, tarball URL, integrity hash, changelog link.- CI in the registry repo runs
validate-pr.yml— schema, license header, tarball download + checksum, manifest replay, optional preview render. - On merge,
publish-index.ymlregeneratesmarketplace.jsonand pushes it tomain. GitHub Pages / CDN serves it as the fetchable marketplace JSON, whilehttps://open-design.ai/plugins/renders the public browser and detail pages over that same source data.
Yanking uses the same PR shape with a yanked: true, reason: "..." patch
to the version JSON. Daemons treat yanked versions as unresolvable but
preserve them for od plugin info <name>@<v>.
Yanking never hard-deletes bytes or metadata. New installs refuse yanked versions; exact lockfile replay may still install with a warning as long as the archive remains reachable and integrity matches.
1.4 Install / resolve flow
od plugin install <name>[@<range>]
→ daemon iterates configured backends in trust order
→ first match: download tarball, verify SHA-256, extract to
daemon-managed plugin storage, write InstalledPluginRecord with
full provenance (sourceMarketplaceId, marketplaceTrust, source URL,
sourceDigest, resolved ref)
→ record the lockfile through daemon-managed storage for reproducibility
od plugin upgrade [--policy latest|pinned] re-resolves against lockfile and
applies new versions atomically (no in-place mutation; new version directory,
swap symlink, rollback on failure).
1.5 Login model
ghis a first-class dependency ofodregistry workflows. Installingodshould ensureghis present when the platform channel can bootstrap it; otherwise the installer fails with exact remediation.od plugin loginwrapsgh auth loginwith Open Design copy, scopes, and host guidance.od plugin whoamiwrapsgh auth statusplusgh api user.od plugin logoutmay wrapgh auth logout, but only after explicit confirmation because it affects the user's global GitHub CLI session.- The daemon never stores GitHub tokens. GitHub.com and GitHub Enterprise auth
stay in
gh; daemon code goes through a narrowGhClientabstraction. - Generic bearer/header/basic/mTLS auth profiles are reserved for future
non-GitHub HTTPS or database backends. They must not leak into
marketplace.json. - Database backend (future) defines its own auth in
RegistryBackend.kind=db; CLI surface stays unchanged.
1.6 Website renderers
Two consumers of the same marketplace.json:
- Official site (open-design.ai/plugins) — static, SSG against
repo-owned
plugins/registry/*/open-design-marketplace.jsonsources. Browse, search, copy install command, render plugin details, preview asset, capability & permission summary, version history, publisher links, and canonical SEO pages.open-design.ai/marketplacecan be kept as an alias once routes are finalized. - Self-hosted third-party site — out of the box, anyone running the
same registry repo template gets the static site as a copy-paste
GitHub Pages action. They publish their own catalog URL, users add it
with
od marketplace add <url>.
UI never special-cases the official catalog beyond the trust tier; the website is one rendering of a generic data source.
1.7 Web app surface (apps/web)
Update apps/web/src/components/PluginsView.tsx from "installed list"
into a multi-source registry browser:
- Tabs: Installed · Available · Sources · Team
- Available: cards grouped by
sourceMarketplaceIdand trust tier. Filter by capability, tag, publisher. Each card: title, version, publisher, trust badge, install button. - Sources: Add URL · Refresh · Remove · Trust toggle · auth status for private catalogs · "view manifest" drawer.
- Plugin detail drawer: provenance line ("from official · trusted · github.com/foo/bar@v0.2.0 · sha256:abcd…"), permissions, README, install command, available versions, yanked-version warning.
The first UI slice has already unlocked Available and Sources using cached
marketplace manifests and existing /api/marketplaces endpoints. Follow-up
work should move large-catalog browsing to typed paginated APIs and add
provenance-aware --from <marketplace-id> install semantics.
1.8 Current implementation slice (2026-05-13 / 2026-05-14)
This repo now has the first registry closure in place:
- Contracts and JSON schema use
official / trusted / restrictedmarketplace trust, and marketplace entries can carryversions,dist,distTags,integrity,manifestDigest,publisher,homepage,license,capabilitiesSummary,deprecated, and yanking metadata while staying passthrough-friendly. - Daemon install and upgrade flows preserve marketplace provenance:
sourceMarketplaceId, entry name/version, marketplace trust, resolved source/ref, manifest digest, and archive integrity. Snapshot records carry the same audit trail for agent/runtime replay. - The packaged daemon seeds built-in
officialandcommunityregistry sources fromplugins/registry/*/open-design-marketplace.json.officialis verified and can also hydrate bundled preinstalls;communityis restricted by default and feeds Available entries for user-initiated installs. - Bundled official plugins now carry
sourceMarketplaceId=officialandsourceMarketplaceEntryName=open-design/<plugin-id>, so they are modeled as preinstalled official registry entries while keeping offline first-run bytes in the runtime image. od plugin loginandod plugin whoaminow delegate togh, and registry publishing now has three paths:--to open-designproduces the human review target/link,--to marketplace-json --catalog <path>upserts a self-hosted static catalog entry, andGithubRegistryBackend.publish/yankproduces deterministic PR mutation payloads for a real GitHub mutator.packages/registry-protocoldefines the backend interface and schemas; daemon now has static, GitHub, and SQLite database-backed implementations sharing the same list/search/resolve/publish/yank/doctor contract.- Version resolution supports exact versions, dist-tags,
^/~ranges, and yanking behavior. Archive downloads verify/store SHA-256 integrity, and a lockfile helper records resolved marketplace provenance for reproducible installs. od marketplace plugins,od marketplace doctor,od marketplace login, versionedod plugin install, policy-awareod plugin upgrade, marketplaceod plugin info, andod plugin yankare implemented as headless surfaces with JSON output where automation needs it.- Home now presents official plugins as
Official starterswith aBrowse registrypath into/plugins;/pluginsremains the registry console (Installed / Available / Sources / Team). apps/landing-pagenow exposes the public SEO renderer at/plugins/plus static per-plugin detail pages. It readsplugins/registry/official,plugins/registry/community, and bundled official manifests at build time, so open-design.ai can show the ecosystem without calling daemon APIs.- The
Create pluginproduct prompt is agent-assisted and explicitly drives scaffold/validate/local install/pack/login/whoami/publish expectations. - Registry evaluation cases now live in
docs/testing/plugin-registry-eval-cases.md. The first covered set locks rawopen-design-marketplace.jsonsource input, populated official seed loading, default community seed loading, provenance/trust inheritance, bundled officialUsebehavior in Available, direct GitHub imports, the Create/Publish agent handoff surfaces, version resolution/yanking, backend parity, registry doctor, archive integrity, lockfiles, and static marketplace-json publishing.
2. Phased plan
P0 — Contract closure (unblocks everything else)
Goal: every later phase can assume one trust vocabulary, full provenance, and a versioned marketplace entry.
- P0.1 Unify trust tier vocabulary. In
packages/contracts/src/plugins/marketplace.ts, renameMarketplaceTrustfromofficial|trusted|untrusted→official|trusted|restricted. Migrate daemon, CLI, UI, fixtures. - P0.2 Marketplace entry v1.1 fields. Extend
MarketplacePluginEntrySchemawith optionalversions[],integrity(sha256),publisher,homepage,license,capabilitiesSummary,yanked. Stay.passthrough()for community extensions (clawhub tags etc.). - P0.3 Install provenance. Plumb
sourceMarketplaceId,marketplaceTrust,marketplacePluginName, and the resolved transport source throughapps/daemon/src/server.tsinstall path (currently around line 3880). TheInstalledPluginRecordalready has these fields — make sure they actually get populated when install comes via marketplace. - P0.4 Default trust inheritance. Installs from
official/trustedcatalogs default totrusted; installs fromrestrictedcatalogs stayrestricted. Document in spec §6 patch. - P0.5 Registry protocol package. New
packages/registry-protocol/with theRegistryBackendinterface, shared zod schemas, and pure tests. No runtime deps.
P1 — Headless / CLI completeness
Goal: every registry action you'd want from the website works on the CLI first, headless, JSON-emitting.
- P1.1 New CLI subcommands.
od marketplace plugins <id> [--json]od marketplace search <query> [--json]od marketplace doctor [<id>]od plugin install <name>@<version|range>od plugin upgrade [--policy latest|pinned]od plugin yank <name>@<version> --reason "..."od plugin info <name> [--version <v>] [--json]od plugin login-> wrapsgh auth loginwith OD-specific host/scope guidance.od plugin whoami-> wrapsgh auth statusplusgh api user. These now cover marketplace plugins/search/doctor/login, versioned install, policy-aware upgrade, marketplace info, yanking, and gh-backed login/whoami.
- P1.2 GitHub backend module.
apps/daemon/src/registry/github-backend.tsimplementsRegistryBackendagainstopen-design/plugin-registry. Uses raw HTTPS/static reads and a narrow mutation client for PR creation, keepinggh/GitHub auth outside daemon persistence. - P1.3 Publish orchestrator, first mutation-capable slice.
GithubRegistryBackend.publish/yankbuilds deterministic registry files and PR payloads;od plugin publish --to marketplace-json --catalog <path>covers self-hosted static catalogs. The release-upload/fork/branch executor remains an adapter on top of the tested mutation contract. - P1.4 Lockfile. The daemon-managed plugin lockfile records resolved
name@version+ integrity +sourceMarketplaceId.od plugin installhonors lock on second run;od plugin upgraderewrites it. - P1.5 Private GitHub catalog auth.
od marketplace login <id>delegates togh auth loginfor the catalog host. GitHub credentials stay ingh, never inmarketplace.jsonorinstalled_plugins. Generic token profiles are reserved for future non-GitHub HTTPS or database backends. - P1.6 Integrity verification. Verify SHA-256 of downloaded tarball
against the marketplace entry's
integrityfield before extracting. Fail closed if mismatch. Store digest on the install record. - P1.7 Headless e2e tests under
apps/daemon/tests/:- add marketplace → search → install by name → run → provenance asserted
in
installed_pluginsrow. - lockfile reproduces same install on a fresh daemon data dir.
- integrity-mismatch tarball is rejected.
- add marketplace → search → install by name → run → provenance asserted
in
P2 — Web app: from "installed page" to "registry browser"
- P2.1 Unlock source management.
/pluginsnow hasInstalled / Available / Sources / Teamtabs. Sources can add URL, refresh, remove, and change trust tier through existing/api/marketplacesendpoints. - P2.2 Available tab entry slice. Available cards are built from
configured marketplace manifests and show Install / Use / Upgrade states.
The bare-name install path now persists marketplace provenance; explicit
--from <marketplace-id>remains follow-up work. - P2.3 Home official shelf semantics. Rename the Home page
Officialplugin shelf copy toOfficial startersorOfficial installed, and add a lightweightBrowse registrypath into/plugins. Home remains fast-use;/pluginsremains registry discovery/management. - P2.4 Agent-assisted Create plugin flow. The
Create pluginaction should start an agent workflow that gathers intent, scaffolds the plugin, writesSKILL.md/open-design.json, validates, installs a local test copy, packs, checksghlogin/whoami, and publishes by opening a GitHub registry PR throughod plugin publish. Current slice upgrades the product prompt, CLI wrapper, marketplace-json self-host publish, and tested GitHub PR mutation payload contract. - P2.5 Plugin detail drawer. Provenance line, permissions, capability
summary, version dropdown, install command (copy-to-clipboard, matches
od plugin install <name>@<version>). - P2.6 Team / Private marketplace UI. Private URL field, auth status
pill, default trust, org allowlist, refresh schedule, audit log link.
Wired to
/api/marketplaces/:id/auth(new). - P2.7 Trust badge consistency. Same
official / trusted / restrictedvisual language across cards, drawer, Sources tab, install confirm modal.
P3 — Official website + ecosystem
- P3.1 Stand up
open-design/plugin-registryrepo shape. Schema, validation workflow, index-publishing workflow, OWNERS, contribution guide. Seed with the bundled plugins currently shipped inplugins/_official/. The local repo now carries the source shape and generated registry inputs; creating the external GitHub repo is an operational launch step, not a code blocker. - P3.2 Static site renderer.
apps/landing-pagenow statically generatesopen-design.ai/pluginsand per-plugin detail routes fromplugins/registry/*/open-design-marketplace.jsonplus bundled official manifests, with SEO metadata, search JSON, andod://detail links. - P3.3 Submission guide.
docs/publishing-a-plugin.md+ zh-CN. The guide must be runnable end-to-end withod plugin init→od plugin pack→od plugin publish, no manual JSON editing. - P3.4 Self-host kit.
docs/self-hosting-a-registry.md— copy theplugin-registryrepo template, pointod marketplace addat it, done. Also documents the future DB-backend swap path so enterprises know the exit option exists. - P3.5
od plugin publish --to marketplace-json. Lets third-party catalog owners accept submissions from their own users using the same CLI by writing/upserting their own staticopen-design-marketplace.json. - P3.6 Registry doctor.
od marketplace doctorvalidates every entry is downloadable, manifest parseable, checksum match, permissions present. Surface in web Sources tab too. - P3.7 Publisher verification hooks. Lightweight GitHub-org publisher metadata is generated for marketplace-json entries and protocol schemas now support verified publishers/signatures. Heavier sigstore/cosign enforcement remains deferred — open question §4.
P4 — Future / non-blocking
- P4.1 DB-backed RegistryBackend. Same interface, SQLite or Postgres. Validates R2.
- P4.2 Search index. Static
open-design.ai/plugins/search.jsonexposes the website search index; CLI still works againstmarketplace.jsondirectly. Typesense/Meilisearch can replace the static file later without changing registry semantics. - P4.3 Web-of-trust badges data hooks. Protocol schemas include optional metrics for downloads, installs, stars, and activity timestamps. Real collection/display stays opt-in per spec privacy stance.
- P4.4 Marketplace signing data hooks. Protocol schemas include optional signature records for GitHub OIDC/cosign/minisign/custom signing. Client-side enforcement is intentionally deferred until the registry service starts emitting signed catalogs.
3. Resolved decisions
- Namespace policy. Registry package ids are
vendor/plugin-name. Flat ids remain a compatibility path for existing local/bundled plugins, but public publish requires the namespaced id. - Plugin source-of-truth repo. The source repo can be any shape that
survives
od plugin validateandod plugin pack. Registry publish requires aplugin.repofield inopen-design.jsonpointing to source. - Tarball hosting fallback. If GitHub Releases are unavailable (enterprise / mirror), raw HTTPS or object-storage archive URLs are accepted with mandatory integrity hash.
- Signing. sigstore/cosign is deferred to P4. Start with PR-author identity + SHA-256, escalate if ecosystem grows.
- Yanking vs deletion. Never hard-delete a version. Only mark it
yanked: truewith reason; new installs refuse, exact existing locks can still replay with warning when integrity matches. - Plugin ID stability. A published package id is immutable. A renamed plugin gets a new id plus alias/deprecation metadata; old id stays traceable for historical installs and lockfiles.
4. Definition of done (registry v1)
R1–R6invariants each have a regression test that fails when violated.- A third party can fork
open-design/plugin-registry, change two config values, run one workflow, and have a working OD plugin source at their own URL — verified with an e2e fixture catalog. - Every UI action in
PluginsView.tsxSources/Available tabs is expressible as oneodCLI invocation, verified by a script that drives both surfaces against the same fixture. - One real third-party publisher (target: a Claude-skills-community
contributor) has published a plugin via
od plugin publishend-to-end without writing JSON by hand.
5. Cross-references
- Trust tier rename touches
packages/contracts/src/plugins/marketplace.ts,apps/daemon/src/cli.ts(marketplace subcommands),apps/daemon/src/server.ts(install path),apps/web/src/components/PluginsView.tsx. - Provenance plumbing touches
apps/daemon/src/server.ts(~line 3880) andapps/daemon/src/cli.ts(~line 1183). - Existing per-plugin runtime work (apply, snapshot, pipeline) is owned by
plugins-implementation.md; this plan does not modify any of those modules.