Skip to content

Proposal: extension registry (build-time vendoring of pinned, browser-only extensions) - #59

Draft
aneeshsathe wants to merge 4 commits into
blygger:mainfrom
aneeshsathe:feat/extension-registry
Draft

aneeshsathe wants to merge 4 commits into
blygger:mainfrom
aneeshsathe:feat/extension-registry

Conversation

@aneeshsathe

Copy link
Copy Markdown
Contributor

This is a proposal for Venkat's ruling, with a working implementation behind it. The design is not settled. It would let third-party code be compiled into the owner's session, and it proposes that blygger.org eventually host the index. Under the project's model routing, both of those are ⚠️ FABLE questions. See docs/extension-registry.md, especially "Open questions".

What it does. This adds a central index. Authors submit Studio extensions to it by PR, and operators pull extensions from it into their own builds. It keeps the rule from docs/extensions.md, no runtime loading: a Studio never fetches or evaluates anything from the registry.

  • The index. registry/index.json is committed empty, with nothing third-party in it. It comes with a Zod schema and a JSON Schema generated from it. An entry pins:

    • an https git repo;
    • a full commit id;
    • a sha256 tree hash;
    • the range of Studio versions it supports.

    It must also say "server": false.

  • npm run ext:add <name> fetches the pinned commit on the operator's machine. It then:

    • verifies the tree hash;
    • checks that the extension is browser-only;
    • checks the import boundary with the TypeScript parser, refusing import(), require() and remote CSS;
    • typechecks the code against the extension API.

    It prints every file and anything flagged for review, then asks before going on. On a yes, it copies the code into the gitignored extensions-vendor/ directory and records the commit and hash in the gitignored extensions.local.json. ext:update and ext:remove work the same way.

  • npm run build compiles vendored extensions in. It re-hashes each one and refuses a tree that was edited after vendoring. A release build uses extensions.json alone, so it can never carry a vendored extension.

  • npm run registry:check validates submissions, and CI runs its offline half. registry:hash lets authors compute their entry's hash. registry:site writes a static browse page; nothing in this PR deploys it.

  • v1 is browser-only. A server half would add routes to openapi.json, and that file has to stay a function of the repository.

Not changed: extensions/catalog.ts, openapi.json, the SDK and extensions.json.

Open questions for Venkat (full list in the doc):

  1. Should third-party code be compiled into the owner's session at all?
  2. Does a listing count as an endorsement, and who reviews submissions?
  3. Where should the index live: this repo, a separate blygger/registry repo, or blygger.org?
  4. How could extensions with a server half be supported?
  5. How is an extension revoked once operators have vendored it?
  6. Should the extension API have its own version, instead of entries naming Studio version ranges?
  7. Should entries be signed?
  8. Should the Studio set a Content Security Policy connect-src?
  9. What licence obligations does vendoring bring?

Tests: test-ui/extension-registry.test.ts covers:

  • schema validation;
  • hash verification against local fixture git repos, with no network access;
  • refusing server halves and import-boundary violations;
  • the gitignore entries;
  • release builds ignoring vendored extensions;
  • refusing a tree edited after vendoring;
  • the CLI's review prompt.

Results: typecheck clean, npm test 1552 passed, npm run test:ui 107 passed, and sdk:generate leaves no diff.

🤖 Generated with Claude Code

@aneeshsathe

Copy link
Copy Markdown
Contributor Author

This PR's failed e2e check is the flaky compose-pwa.spec.ts:179, which fails on main too. It isn't caused by this change. #64 fixes the race behind it. I can't re-run fork CI myself; a re-run, or a rebase after #64 lands, should turn it green.

🤖 Generated with Claude Code

@vgururao

Copy link
Copy Markdown
Contributor

Thanks, Aneesh, and sorry this has sat for a week. You're right that this needs a ruling and not just a review: compiling third-party code into the owner's session, and blygger.org hosting the index, are both spec-level calls under our routing. It's now queued for the next spec round. That round opens 0.4 first, so expect a ruling in a round or two, not in days. The working implementation will make it much easier to rule on, thank you for building it.

#64 has merged since your note, so rebasing onto main should clear the compose-pwa flake.

aneeshsathe and others added 4 commits October 18, 2026 13:08
Proposal groundwork for the extension registry (docs/extension-registry.md,
pending Venkat's ruling). A browser-only extension vendored into the
gitignored extensions-vendor/<name>/ and locked under "vendored" in
extensions.local.json compiles in like a catalogued one. Release builds
ignore the local file, so they can never carry one; BLYG_EXTENSIONS=all
stays the catalogue. The build re-hashes each vendored tree and refuses one
edited since it was vendored, or one with a server half.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A proposal with a working implementation, pending Venkat's ruling: it
compiles third-party code into the owner's session and proposes hosting on
blygger.org. Build-time vendoring only; no Studio loads anything at run time.

- registry/index.json (empty: nothing third-party) and index.schema.json,
  generated from the Zod schema in scripts/registry-schema.ts: full commit
  ids, https sources, a tree hash, a Studio range, and server: false (v1 is
  browser-only, because openapi.json must stay a function of the repository).
- ext:add/update/remove fetch the pinned commit from git objects on the
  operator's machine (https only, or a --from mirror), check the tree hash,
  layout, import boundary (TypeScript parser; no import()/require(), no remote
  CSS) and a typecheck against the extension API, print every file and the
  review flags, and vendor only after a yes or --yes.
- registry:check validates submissions (CI runs --offline, no network);
  registry:hash prints an entry's sha256; registry:site emits a static,
  script-free browse page into build/ and deploys nothing.
- test-ui/extension-registry.test.ts: schema, hash, refusals, gitignore,
  release builds without vendored extensions, the CLI, all against throwaway
  git repositories built from registry/fixtures/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/extension-registry.md: status (a proposal for Venkat's ruling), the
security model, operator and author guides, the reviewer checklist, the
tree hash, the in-repo extensions written as example entries, why v1 is
browser-only, and nine open questions. docs/extensions.md points at it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
catalog.ts imports the extensions' server contracts, which since main's
lineage-glyph contract reach src/types.ts and its Worker types; the UI
typecheck (tsconfig.ui.json) reaches registry-lib through the registry test
and failed on D1Database/R2Bucket/Ai. Every catalogued name is its own
directory, so the directory listing already covered them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aneeshsathe
aneeshsathe force-pushed the feat/extension-registry branch from 0ba4fa0 to 88e6d48 Compare October 18, 2026 20:33
@KyleAMathews

Copy link
Copy Markdown
Contributor

Plugins/extensions for web apps are incredibly tricky FYI — I'm not sure this is a good idea especially for self-deployed apps etc. I'd just assume people can slop fork for their own tweaks + find and install maintained slop forks.

@vgururao

Copy link
Copy Markdown
Contributor

I think I want to stop at enabling certain useful hooks but not a plugin marketplace or a full-blown programmable surface. But otoh slop-forking may be too limiting. Been sitting on this while I think it through. Maybe a middle ground is publishing a set of soft design principles for safe and non-obnoxious mods.

@KyleAMathews

Copy link
Copy Markdown
Contributor

I had a draft of a blog post about design grammar UI design -- the basic idea is you treat the app as a protocol of sorts with a design grammar where everything works together nicely.

So it is in theory possible to do something like this but it does seem like a misuse of our energy as the UI isn't really that important it seems for blygger figuring out what it is. Innovation can happen in forks and get pulled in as it proves itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants