cyberine
Design notes

Plugin Marketplace / Discovery Registry — Build vs Defer (T542)

Scope

This note decides ONE thing: whether Cyberine should build a hosted marketplace / discovery registry for plugins — a remote index a user can search/browse, with install-from-registry as a third source alongside local-path and git-url install. It does NOT re-litigate the base plugin system, which is already shipped and is treated here as a fixed foundation.

What already exists (the foundation, not up for debate)

The installable plugin system shipped in bb325c5 (feat(plugins): add installable plugin system (#1)), built across P0-P6 of the original plan (todos/ROADMAP.md:34-99):

  • Contract types (src/plugins/types.ts) — PluginManifest (name, version, description, kind[], optional entry/mcp/cyberine semver range/env/trusted), the PluginApi surface a code plugin's register() touches (registerTool/registerJudge/registerWorkerProfile/registerAdapter/ registerHook/registerMcpServer), and the accumulator PluginRegistry the P1 build seam consumes.
  • Loader (src/plugins/loader.ts) — loadPlugins()/ensurePluginsApplied() scan a single trusted directory (pluginsRoot(): CYBERINE_PLUGINS_DIR or <cyberineHome()>/plugins, i.e. ~/.cyberine/plugins), validate each cyberine-plugin.json with zod, apply a semver compatibility gate, connect declarative mcp specs out-of-process via McpToolAdapter, and dynamically import() a code plugin's entry module in-process. The security banner at the top of the file (lines 18-31) is explicit: the trusted-dir gate is the whole security boundary, and it must never widen to a project/cwd-relative path.
  • CLI (src/commands/plugins.ts, wired as cyberine plugin ..., documented in USAGE.md around line 5617) — list, info <name>, doctor, install <src> [--yes], remove <name> [--yes], enable <name>, disable <name>. install already accepts either a local directory path or a git URL (including a github:owner/repo shorthand, normalizeGitUrl in plugins.ts:234-241) — it clones/copies into pluginsRoot() after validating the manifest and, for code plugins, an explicit confirm gate (confirmInstall, plugins.ts:130-153).
  • Two plugin kinds — mcp (declarative, out-of-process, spawned via the existing McpToolAdapter, the safe default) and code (entry module, in-process, full privileges, gated behind the trusted-dir + confirm). Two bundled examples ship in examples/plugins/ (clock-tool, everything-mcp).

So today: a user who has a plugin's source (a local checkout or a git URL they already know) can install it in one command, and the loader/CLI correctly validate, gate, and report on it. What is missing is entirely upstream of that — there is no way to find a plugin without already knowing where it lives.

The gap this note is about

A discovery/marketplace layer would add:

  1. A remote index format — some JSON document (or small set of them) listing known plugins: name, version(s), description, kind, source (git URL or npm-style package ref), maybe a trust/verification flag. Hosted somewhere (a static file in a GitHub repo at minimum; a real registry service at the other extreme).
  2. A command surface — cyberine plugin search <query> / cyberine plugin browse (list what the index has, independent of what's installed locally) — new read-only subcommands alongside the existing list/info/doctor.
  3. Install-from-registry — cyberine plugin install <name> resolving through the index to a source (most naturally: resolve to a git URL, then hand off to the existing cmdPluginInstall git path — same clone, same validateManifestDir, same confirmInstall gate, same trusted-dir write target). Discovery would be additive plumbing in front of the install path, not a new install path — the trusted-dir gate and the code-plugin confirmation stay exactly as they are.

None of this touches the loader's trust boundary: a plugin found via the registry still has to pass through validateManifestDir + confirmInstall + land in pluginsRoot() exactly like a manually-supplied git URL does today. Discovery only changes how the user finds the <src> argument; it does not change what happens once they have it.

Weighing build vs defer, for THIS project at THIS stage

Facts on the ground (from .claude/rules/user-vibe-stage.md and this repo's actual state):

  • The repo is declared Sandbox / early-dev — not deployed anywhere, no production, a self-hosted operator CLI/TUI tool used by its own author. It is not a consumer SaaS with an installed base that would benefit from browsing a catalog.
  • Install already works end-to-end via local path and git URL — the mechanical gap ("can I install a plugin I have a link to") is closed. The only gap is discovery ("what plugins exist that I don't already know about").
  • There is no evidence of any third-party plugin author. The only plugins that exist are the two bundled examples in examples/plugins/ (clock-tool, everything-mcp), both written by this project to exercise the loader, not independent contributions. A marketplace with zero real listings is a page that says "nothing here" — it would be built entirely on speculation about future supply.
  • A marketplace has two sides (supply of plugins, demand from searchers) and right now there is measurably zero of the first and no signal of the second (no user has asked cyberine plugin search didn't work, because nobody outside this project has written a plugin to search for). Building the discovery layer now would be building infrastructure for a market that does not exist yet — the classic premature-marketplace trap.
  • The cost of building it now is not trivial either: a remote index needs a hosting decision, a trust/verification story for third-party listings (do we vet a listing before it's searchable, or just mirror whatever a plugin author registers?), and ongoing curation — none of which has an owner beyond the sole operator today.

Against that, the case for building anyway would be: "cheap to stub, and an empty search command costs nothing." That's true for a trivial stub, but a stub that returns nothing is not the feature being asked for (T542 asks for a real search/browse against a remote index) — building the real thing (hosting + format + trust story) is the part that isn't cheap, and there's no one to consume it yet.

Decision: DEFER (no marketplace/discovery layer; tombstone this note as the record)

Do not build cyberine plugin search/browse or a remote index now. The base plugin system already solves the mechanical problem (install once you have a source); discovery infrastructure ahead of any third-party plugin ecosystem is solving a problem that does not exist yet, for an audience (external plugin authors and searchers) this project does not currently have.

If a middle path becomes attractive before the full signal below fires, the cheapest version worth reconsidering is a static curated JSON index (e.g. a single plugins-index.json committed to this repo or a gist, hand-maintained, no hosting infra, no submission process) consumed by a thin cyberine plugin search that fetches it and filters client-side, still installing through the existing git-URL path. That is a few hours of work, not a service — but even that is not worth doing until there is at least one listing to put in it that isn't one of the project's own examples.

Re-open trigger

Re-open this decision (and default to the minimal curated-index middle path first, a full service registry only if the curated index itself becomes a bottleneck) as soon as ANY of:

  • A real third-party plugin exists — someone other than this project's own author has written and published a cyberine-plugin.json-conformant plugin (even one is the signal; it proves the supply side is non-zero).
  • A user explicitly asks for discovery — "how do I find plugins" / "is there a list of plugins" surfaces as a real request, not a speculative one.
  • The bundled examples stop being the only plugins in existence — e.g. this project or a collaborator starts maintaining more than a couple of plugins across separate repos, making "I have to remember every git URL" an actual friction point rather than a hypothetical one.

Non-decision

This note does not touch the base plugin system (src/plugins/*, src/commands/plugins.ts) in any way — no code in this repo was changed as part of this decision. It also does not propose deprecating or hiding the existing install <git-url> path, which remains the correct way to install a specific known plugin regardless of what happens with discovery.