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[], optionalentry/mcp/cyberinesemver range/env/trusted), thePluginApisurface a code plugin'sregister()touches (registerTool/registerJudge/registerWorkerProfile/registerAdapter/registerHook/registerMcpServer), and the accumulatorPluginRegistrythe P1 build seam consumes. - Loader (
src/plugins/loader.ts) —loadPlugins()/ensurePluginsApplied()scan a single trusted directory (pluginsRoot():CYBERINE_PLUGINS_DIRor<cyberineHome()>/plugins, i.e.~/.cyberine/plugins), validate eachcyberine-plugin.jsonwith zod, apply a semver compatibility gate, connect declarativemcpspecs out-of-process viaMcpToolAdapter, and dynamicallyimport()a code plugin'sentrymodule 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 ascyberine plugin ..., documented inUSAGE.mdaround line 5617) —list,info <name>,doctor,install <src> [--yes],remove <name> [--yes],enable <name>,disable <name>.installalready accepts either a local directory path or a git URL (including agithub:owner/reposhorthand,normalizeGitUrlinplugins.ts:234-241) — it clones/copies intopluginsRoot()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 existingMcpToolAdapter, the safe default) and code (entrymodule, in-process, full privileges, gated behind the trusted-dir + confirm). Two bundled examples ship inexamples/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:
- 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).
- 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 existinglist/info/doctor. - 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 existingcmdPluginInstallgit path — same clone, samevalidateManifestDir, sameconfirmInstallgate, 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 searchdidn'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.
ContextQ Integration — Cyberine long-term memory on the Agent Memory Layer
Status: design spec (drives implementation). Grounded against ContextQ as it ships today (shared-context-server, agent layer migration 0043) and Cyberine memory waves 1-4.
Worker-profile eval coverage (T678)
Generated by npx tsx scripts/t678-profile-coverage.ts --write. Re-run it after any fleet dispatch to refresh; do not hand-edit.