The day-zero "store" for outl plugins: a single versioned registry.json that the CLI and GUI clients read to list and search installable plugins.
No server, no API — just a JSON file, served statically.
Clients fetch it from:
https://plugins.outl.app/registry.json
The repo stays a clean index — the per-plugin bundles are not committed.
A Netlify build step (scripts/build.mjs) reads registry.json, downloads each plugin's plugin.json + bundle from its GitHub repository, and writes them under /p/<id>/, which is then served at https://plugins.outl.app/p/<id>/….
netlify.toml serves everything with a JSON content-type and permissive CORS (so the desktop/mobile webviews can fetch cross-origin), plus index.html as the landing page.
To deploy: connect this repo to a Netlify site and point the plugins.outl.app custom domain at it.
Every push to main rebuilds (re-fetching the bundles) and publishes.
Pin the bundles to a tag by setting OUTL_REF in the Netlify site env (defaults to main).
| File | Purpose |
|---|---|
registry.json |
The index every client reads (https://plugins.outl.app/registry.json). |
schema/registry-v1.json |
JSON Schema the index validates against (CI + editor autocomplete). |
scripts/build.mjs |
Netlify build: downloads each plugin's bundle into /p/<id>/ (a build artifact, gitignored). |
netlify.toml |
Hosting config — build command, content-type, CORS, cache headers. |
index.html |
Landing page at the domain root. |
The bundle host: a client's "tap to install" downloads
https://plugins.outl.app/p/<id>/plugin.json+ the bundle, validates the manifest, freezes the bundle hash, and installs — the same path a localoutl plugin install <dir>takes.
Open a PR adding an entry to registry.json:
Rules:
id,capabilities, andpermissionsmust match the plugin'splugin.json(the install verifies the manifest anyway).repositoryis whatoutl plugin installresolves:outl plugin install github:user/repoclones the repo at the newest semver tag (or…#v1.2.0to pin one).- Keep
versionsnewest-last; bumplateston a new release.
Entries are validated against schema/registry-v1.json in CI.
Today, install directly from a plugin's GitHub source (the repository field of its entry):
outl plugin install github:user/repo # newest semver tag
outl plugin install github:user/repo#v1.2.0 # pin a tagIn-client discovery (outl plugin search + a browse/install screen in the desktop & mobile apps that read this registry.json) is the next step.
A hosted registry (registry.outl.app) with full-text search and install counts comes later, only when volume justifies the infrastructure — the schema here is forward-compatible with it.
{ "id": "app.outl.examples.todo-archiver", // reverse-DNS, MUST match the plugin's plugin.json `id` "name": "TODO Archiver", "description": "One sentence on what it does.", "author": "your-handle", "repository": "github:user/repo", // install source; subdir ok: github:user/repo/plugins/foo "category": "productivity", "keywords": ["todo", "archive"], "capabilities": ["op-hook", "slash-command"], // mirror plugin.json — drives discovery filters "permissions": ["read-page", "write-page"], // mirror plugin.json — users see the ask before install "latest": "1.0.0", "versions": ["1.0.0"] // published tags, newest last }