RFC: Decentralized Plugin Registry - #694
Conversation
|
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | db90d32 | Jul 08 2026, 06:51 AM |
Scope checkThis PR changes 1,131 lines across 3 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
PR template validation failedPlease fix the following issues by editing your PR description:
See CONTRIBUTING.md for the full contribution policy. |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-moderation
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
aa184b6 to
b9f7c20
Compare
|
One immediate thought is that supporting native plugins that bypass the sandbox may be worth digging into. It somewhat goes against the idea of EmDash bringing secure plugins as a replacement to Wordpress. Mainly because the majority of end users likely won’t know/understand/care about the difference. All end users are likely to look at is functionality and more than likely just blindly install the plugin if it looks to do what they expect, regardless of if it’s sandboxed. At that point it negates the whole idea of the sandbox. Also, it disincentivizes plugin authors from building for the sandbox and to rather just take the easier, native, path. |
|
@BenjaminPrice yeah, that's a valid concern. The reason I thought that it was ok on balance is because the install process for a sandboxed plugin is so much easier: just click and it works, vs needing to npm install and add it to the config. There's also the fact that this RFC doesn't specify how these will actually be displayed – and some clients may choose to not display native plugins at all. I'd say this would probably be the case for managed hosts. |
|
Oh this is exciting, fantastic work @ascorbic. Reading this mostly through an atproto lens... Overall, this feels very protocol-native: publishing to author's PDS, using the Relay and App View to aggregate, with clients to query. Love it! There's also the old familiar problem of recentralization creeping in via the biggest App View being the one Emdash maintains. It's a familiar one! The atproto primer is so good. Lexicons Are you certain you want to tie everything to The longer text fields for Bundling the icon and screenshots into the tarball feels like it could be problematic. Does this mean the App View, or any directory client, would need to download the full bundle and extract the images in order to display them? I think a more idiomatic approach would be to include them in the Lexicon, maybe similar to how a bsky record includes embeds. Setting There's a lot of variability in the Lexicon based on the type of package it is (native vs. sandboxed). Feels like a good candidate for a A sandboxed release: {
"$type": "com.emdashcms.registry.release",
"package": "at://did:plc:abc/com.emdashcms.registry.package/gallery",
"version": "1.0.0",
"integrity": "sha256-...",
"source": {
"$type": "com.emdashcms.registry.defs#sandboxedSource",
"url": "https://...",
"capabilities": ["read:content"],
"allowedHosts": ["images.example.com"]
},
"createdAt": "..."
}A native release: {
"$type": "com.emdashcms.registry.release",
"package": "at://did:plc:abc/com.emdashcms.registry.package/seo",
"version": "1.0.0",
"integrity": "sha256-...",
"source": {
"$type": "com.emdashcms.registry.defs#nativeSource",
"npmVersion": "@example/emdash-seo@1.0.0"
},
"createdAt": "..."
}One way to test this would be to add a hypothetical third type — if it doesn't break existing records, it's probably correct. If it requires new upstream fields, not there yet. Consider making The Lexicon evolution section is smart and a good set of best practices. CLI Really love the commitment to using OAuth over app passwords. Not always an easy thing on the CLI, excited to see your implementation! Misc The moderation/squatters issue is potentially quite real; the directory landing before review/reports/labelers could be problematic. There's a period where Is there a migration story for existing plugins? Or a plan for communicating to them directly? Related, what's the discovery mechanism for updates once a plugin is installed? How does an admin know there's a new version, if there are breaking changes, security issues, etc. Consider adding a deprecation mechanism (maybe that's just a field in the lexicon?) Multiple authors feels like something worth resolving sooner rather than later. |
92444a8 to
c5c7e9b
Compare
|
A few additional thoughts: Native plugins in the registry Expanding on my earlier comment, I think this needs more design attention before landing. The RFC currently presents sandboxed and native plugins side by side in a unified registry, with the install flow adapting to the type. The concern is what this looks like to the end user. A non-technical site owner browsing the directory sees two plugins that do the same thing. One is sandboxed with declared capabilities. One is native with full system access. Both show up in the same search results, with the same visual treatment. The type difference is a metadata field, not a prominent trust signal. The RFC says "some clients may choose to not display native plugins at all" and that the install friction difference (one-click vs npm install + config change) is a natural deterrent. I think that underestimates the problem. If the directory website (not the admin UI) lists both types, someone Googling "emdash gallery plugin" might land on the native one and follow the install instructions without understanding what they're opting into. Managed hosts can hide native plugins in their admin UI, but the public directory is where discovery happens for new users. @jimray's point about squatting compounds this. Pre-labelers, a native plugin squatting on a name like Not arguing to remove native plugins from the registry, the unified discovery is genuinely useful. But I think the RFC should say more about how the directory UI distinguishes them and what the default presentation should be. At minimum:
Reviews, labelers, and the pre-labeler gap The RFC defers reviews, moderation, and labelers to follow-on RFCs, and cites #296 as the design basis for that work. I'd like to suggest that at least the initial labeler work happens in parallel with the registry implementation rather than as a follow-on. Launching the directory without any trust signals, even basic ones, creates a window where the squatting and abuse problems @jimray flagged are real and unmitigated. Ideally the registry and at least one labeler ship together. Happy to help draft or contribute to that work. Some things I've been thinking about that might be useful:
Happy to write any of this up in more detail or take a first pass at the follow-on RFC. Key management and the PDS/MST approach @chuckadams' comment in #296 about FAIR's key management challenges is worth flagging here. They found that private keys were too sensitive to store in a WP database, which led to passphrase encryption requirements and UX complexity around key prompting. Still an open design issue in FAIR Beacon. The RFC's approach of using repo-level MST signing, where the PDS handles the keys and publishers never directly manage them, sidesteps this entirely. The publisher authenticates via OAuth, the PDS signs the records, and there's no plaintext key file sitting on disk. This is a genuine advantage of building on ATProto's signing infrastructure rather than rolling explicit per-publisher key management. Worth calling this out as a design rationale in the RFC itself, since it's a concrete example of where the ATProto approach pays off vs. the alternatives. |
|
I hope I'm not too late to the party.
3. Sandboxed/native plugins: supporting @BenjaminPrice comment, I understand the rational but one of the "selling point" of emdash was a better/more secure plugin ecosystem. I would expect the two type of plugins to have clear boundaries for that very reason. And this should not be only UX/UI On my second point, why not prepare the place for a community driven review system (not implementing it with the first batch but setting us up for that). I'm currently working on that issue (not for emdash plugins) and I'm leaning toward using a public git repository to store assessments and have automated + community driven assessment. For our plugins it could mean a emdash-plugins repo. Plugin authors can publish .md with all relevant informations and source code. TBD process to elevate a plugin from unreviewed to stage 1, 2 3 reviewed. Not saying to set it up from the get go, but at least having a first step and extend the current setup with small, stable trust-tier enum carried alongside the runtime variant (something like tier: "sandboxed" | "native-unreviewed" | "native-reviewed" | "native-firstparty"). And that way avoid having to retroffit the model for the first party plugins you mention. 4. Every plugins are considered the same, same as above, we may need at least to scaffold authoring / trust / security early on. I would add a bit of parity between ssandbox and native, even if not enforced for native, #nativeRuntime should require a structured declaredAccess block: things like filesystem: "read" | "write" | "none", network: HostPattern[] | "any", processes: bool, env: string[], astroHooks: string[], addsRoutes: bool, addsMiddleware: bool. That way at install, and afterwards, admins can have a clear vision of what plugins "do". I am not super expert on Astro, and that should be for later, but shouldn't Astro include a "failsafe" in case a plugin doesn't match the signed release? Probably not a day one thing though. Lastly, though it's related to the topic it's probably a bigger discussion, but the separation between sandbox and native should be stronger, that may mean going down the road of having their own endpoints. To be able to have different security settings/rules later down the road. But it's great to see this topic moving forward thank you so much :) |
Establishes rfcs/ as the home for EmDash's lightweight RFC process, with a README describing the two-step Discussion -> PR flow (simplified from Astro's) and a template for future RFCs. RFCs are required to link back to their motivating Discussion(s) via the frontmatter. Moves the in-progress plugin registry proposal from plans/ into rfcs/0001-plugin-registry.md with frontmatter citing #296 and #307 as prior discussions.
- Transition trust model to leverage ATProto primitives (MST, domain as handle) - Defer native plugin support to future RFC - Clarify schema evolution relies on ATProto/FAIR standard practices - Outline AppView role and UI-driven update polling - Detail embedding EmDash extension metadata using 'unknown' lexicon type
- Adopt atproto-native field naming (lowerCamelCase) over FAIR's kebab/snake-case, with cross-transport translation at the aggregator - Drop HAL _links from records; use co-located collection enumeration - Merge plugin.json into manifest.json as single source of truth - Update auth section to reflect deployed granular OAuth scopes and explain CI/CD app-password trade-off honestly - Allow CI app-password credentials only via env vars, never flags - Add mirror policy (OSI-approved licenses only by default) - Specify multibase hash codecs and id/version validation rules - Expand threat model with stolen CI credential, falsified labels, and permission-set Lexicon hijacking - Add label conventions, success criteria, and dependency-ordered implementation plan - Use "aggregator" (FAIR's term) instead of "AppView" (atproto jargon) in body text; introduce the equivalence in the Primer - Fix broken anchor references and normalise atproto capitalisation
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | db90d32 | Jul 08 2026, 06:51 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-perf-coordinator | 46962ad | May 13 2026, 06:12 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-i18n | 46962ad | May 13 2026, 06:12 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 8cc3196 | Aug 26 2026, 09:24 AM |
The aggregator now exposes its read API as XRPC under com.emdashcms.aggregator.* (or pm.fair.aggregator.* if FAIR adopts the namespace) rather than as a custom /v1/* REST surface. This unifies the schema system: records and APIs are both Lexicon-defined. atproto SDKs in any language pick up the API by codegen, the aggregator participates in standard service-discovery, and non-atproto clients can still hit the endpoints with plain fetch or curl. No REST shim is provided in v1. Adds an XRPC entry to the AT Protocol Primer, updates the API surface table to list NSIDs, updates the install-flow diagram to use /xrpc/ paths, and rewrites the client library example to wrap an XRPC agent.
|
I'd done a rewrite that should bring it a lot closer to FAIR, and brings in some of the changes in the protocol recently. I'd really appreciate feedback, particularly from @BenjaminPrice and @toderash! I've got a bit more detail on the atproto side too, so @jimray's thoughts would be great too. |
Releases now carry an explicit `package` field naming the parent profile's slug, and the rkey shape is `<package>:<version>`. This fixes a protocol-level ambiguity where a publisher with multiple plugins couldn't be paired with the right release. Also restricts the version grammar to a rkey-safe semver subset (drops support for build metadata `+...`, since `%` is not a permitted rkey character and atproto rkeys forbid percent-encoding). Updates the install flow to use the aggregator's listReleases path for package-scoped enumeration (atproto's listRecords has no server-side rkey prefix filter; PDS-direct fallback is a full collection scan). Adds an adversarial test for cross-package release confusion and updates the createRelease example to include the package field.
|
The FAIR unification is a strong rewrite — adopting I'd still like to see a small amount of forward-compatible scaffolding land in v1, on the EmDash extension specifically. The cost is two fields in a namespace you fully control; the upside is avoiding a retrofit against records already sitting in publishers' PDSs by the time native plugins or graduated trust tiers come back into scope. 1. Reserve Add the field now, even though v1 only ever writes Clients treat unrecognised values as untrusted. When the native follow-on RFC lands, every existing record is already shape-correct — no migration, no inferred-default ambiguity, no question of how a v1 client should treat a record without the field. 2. Promote Today the extension carries flat declaredAccess: {
network?: "none" | { hosts: HostPattern[] } | "any";
filesystem?: "none" | "read" | "write";
processes?: boolean;
env?: string[];
astroHooks?: string[];
addsRoutes?: boolean;
addsMiddleware?: boolean;
// sandbox-specific (current fields, retained here)
capabilities?: Capability[];
allowedHosts?: HostPattern[];
}For sandboxed plugins, the sandbox enforces these — no behaviour change in v1. For native plugins later, the same block is purely declarative; the admin install UI surfaces what the plugin claims to do, with no enforcement guarantee. Same renderer, same shape, different trust model. 3. Aggregator XRPC: take a The XRPC adoption is great. While the surface is being defined, please reserve a 4. Capability-consent UI renders structured-ready The capability-consent dialog should render The combined ask is small — |
|
This PR has been inactive for 14 days. It will be closed automatically in 7 days if there is no further activity. If you're still working on this, please push an update or leave a comment. |
|
This PR has been inactive for 14 days. It will be closed automatically in 7 days if there is no further activity. If you're still working on this, please push an update or leave a comment. |
|
This PR has been inactive for 14 days. It will be closed automatically in 7 days if there is no further activity. If you're still working on this, please push an update or leave a comment. |
There was a problem hiding this comment.
This is a reasonable architectural direction. The proposal is grounded in the accepted Discussions it links (#296 and #307), fits the RFC process described in rfcs/README.md, and honestly grapples with the trade-offs between FAIR, atproto, and EmDash's own constraints. As a draft RFC it is appropriate for the repo.
However, the RFC text is not internally consistent with the lexicon files that ship in the same PR. I read the full diff, the RFC, the AGENTS.md conventions, and the lexicons under lexicons/com/emdashcms/experimental/. Because this PR contains no runtime code, the only concrete source of truth for the protocol is those lexicons, and the RFC repeatedly contradicts them. The four blocking issues below should be resolved before merging:
- Namespace mismatch — the RFC describes stable/stable-looking NSIDs (
pm.fair.package.*,com.emdashcms.publisher.*,com.emdashcms.aggregator.*) while every shipped lexicon usescom.emdashcms.experimental.*. declaredAccessvocabulary mismatch — the RFC normatively describesemail.events,email.transport,page.fragments, andusers.read, but the release-extension lexicon only definescontent,media,network, andemail.send.- Artifact required fields — the RFC table marks
artifact.urlandartifact.checksumas optional, but the release lexicon requires both. - Version character set — the RFC says
_and~are permitted in version strings, then gives a grammar that forbids them, and the release lexicon forbids them.
I also flagged one smaller suggestion about the release-response envelope example. Fix the four inconsistencies above and the RFC will be in good shape to land.
|
|
||
| For follow-on features that require rapid iteration (e.g., reviews or reports), developers may use an experimental marker in the NSID (e.g. `com.emdashcms.experimental.review`). However, the core registry records (`pm.fair.package.profile`, `pm.fair.package.release`, and `com.emdashcms.package.releaseExtension`) are stable. |
There was a problem hiding this comment.
[needs fixing] The RFC is inconsistent with its own lexicons on namespaces. Line 677 calls the core records "stable," the body repeatedly refers to package/release records as pm.fair.package.*, and the API-surface table (lines 884-888) lists com.emdashcms.aggregator.*. But the lexicons shipped in this PR all use com.emdashcms.experimental.* (e.g. com.emdashcms.experimental.package.profile, com.emdashcms.experimental.aggregator.getPackage, etc.). The Implementation Plan does mention an experimental phase, but the rest of the document does not, so a reader generating a client from the lexicons will get a different NSID than the RFC describes.
| For follow-on features that require rapid iteration (e.g., reviews or reports), developers may use an experimental marker in the NSID (e.g. `com.emdashcms.experimental.review`). However, the core registry records (`pm.fair.package.profile`, `pm.fair.package.release`, and `com.emdashcms.package.releaseExtension`) are stable. | |
| For follow-on features that require rapid iteration (e.g., reviews or reports), developers may use an experimental marker in the NSID (e.g. `com.emdashcms.experimental.review`). However, the core registry records (`com.emdashcms.experimental.package.profile`, `com.emdashcms.experimental.package.release`, and `com.emdashcms.experimental.package.releaseExtension`) are experimental while the stable namespace is pending. |
More broadly, the RFC should adopt the com.emdashcms.experimental.* NSIDs consistently throughout — including the API-surface table and the publisher sections — and only reference pm.fair.* / com.emdashcms.package.* as the planned stable target after the FAIR decision is made.
| **`email`** — sending mail through the host's mail service and participating in its delivery pipeline. | ||
|
|
||
| | Operation | Description | | ||
| | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `send` | Plugin may send mail. Constraint vocabulary reserved for follow-on RFCs (rate limits, recipient allow-lists, etc., per [Constraints](#constraints)). | | ||
| | `events` | Plugin observes and may mutate every outgoing message, before and/or after send — including mail originated by the host and by other plugins, not just its own. | | ||
| | `transport` | Plugin becomes the host's mail transport: every message the site sends is delivered through it. Exclusive — a site has at most one transport; installing replaces the current one. | | ||
|
|
||
| **`page`** — participation in rendered page output. | ||
|
|
||
| | Operation | Description | | ||
| | ----------- | ---------------------------------------------------------------------------------------------------------------- | | ||
| | `fragments` | Plugin injects script and/or style fragments into rendered pages. Active content in the page origin; high trust. | | ||
|
|
||
| **`users`** — access to site user records. |
There was a problem hiding this comment.
[needs fixing] The RFC describes a v1 declaredAccess vocabulary that the shipped lexicon does not implement. Lines 586-590 list email.events and email.transport as normative operations, and lines 594-600 add page.fragments and users.read. But lexicons/com/emdashcms/experimental/package/releaseExtension.json only defines content, media, network, and email, and under email only send. Because the RFC says clients MUST reject unknown top-level categories and unknown operations within a known category, records using the RFC-described operations would be rejected by a lexicon-conforming validator, while runtimes following the RFC would reject records that do not include them. The two must agree before merge.
Either add events/transport under email and add the page and users categories to the release-extension lexicon, or remove those operations from the RFC and defer them to the follow-on RFC.
| | `url` | string | no | URL where the artifact can be downloaded. | | ||
| | `signature` | string | no | Optional cryptographic signature of the artifact. Retained for strict FAIR compatibility, but EmDash clients do not require it as integrity is proven via the atproto MST signature over the record's `checksum`. | | ||
| | `checksum` | string | no | Checksum of the artifact in [multibase](https://github.com/multiformats/multibase)-encoded [multihash](https://github.com/multiformats/multihash) format (per proposed [FAIR PR #82](https://github.com/fairpm/fair-protocol/pull/82)). EmDash clients MUST support `sha2-256` (multihash code `0x12`) and SHOULD support `sha2-512` (`0x13`) and `blake3` (`0x1e`). The base prefix character is part of the value (we recommend `base32`, prefix `b`, for compactness and case-insensitivity). Clients reject artifacts whose checksum uses an unsupported hash function rather than skipping verification. | |
There was a problem hiding this comment.
[needs fixing] The artifact properties table marks url (line 476) and checksum (line 478) as optional (no in the Required column), but lexicons/com/emdashcms/experimental/package/release.json defines the artifact with "required": ["url", "checksum"]. A release artifact is not usable without both a download URL and an integrity checksum, so the table contradicts the schema.
| | `url` | string | no | URL where the artifact can be downloaded. | | |
| | `signature` | string | no | Optional cryptographic signature of the artifact. Retained for strict FAIR compatibility, but EmDash clients do not require it as integrity is proven via the atproto MST signature over the record's `checksum`. | | |
| | `checksum` | string | no | Checksum of the artifact in [multibase](https://github.com/multiformats/multibase)-encoded [multihash](https://github.com/multiformats/multihash) format (per proposed [FAIR PR #82](https://github.com/fairpm/fair-protocol/pull/82)). EmDash clients MUST support `sha2-256` (multihash code `0x12`) and SHOULD support `sha2-512` (`0x13`) and `blake3` (`0x1e`). The base prefix character is part of the value (we recommend `base32`, prefix `b`, for compactness and case-insensitivity). Clients reject artifacts whose checksum uses an unsupported hash function rather than skipping verification. | | |
| | `url` | string | yes | URL where the artifact can be downloaded. | | |
| | `signature` | string | no | Optional cryptographic signature of the artifact. Retained for strict FAIR compatibility, but EmDash clients do not require it as integrity is proven via the atproto MST signature over the record's `checksum`. | | |
| | `checksum` | string | yes | Checksum of the artifact in [multibase](https://github.com/multiformats/multibase)-encoded [multihash](https://github.com/multiformats/multihash) format (per proposed [FAIR PR #82](https://github.com/fairpm/fair-protocol/pull/82)). EmDash clients MUST support `sha2-256` (multihash code `0x12`) and SHOULD support `sha2-512` (`0x13`) and `blake3` (`0x1e`). The base prefix character is part of the value (we recommend `base32`, prefix `b`, for compactness and case-insensitivity). Clients reject artifacts whose checksum uses an unsupported hash function rather than skipping verification. | |
| Both halves of the rkey are subject to validation rules: | ||
|
|
||
| - The portion before `:` MUST equal `package` and follow the same grammar as `slug` on the package profile. | ||
| - The portion after `:` MUST equal `version`, byte-for-byte. The version string MUST therefore be composed only of characters allowed in atproto record keys: ASCII letters (`a-zA-Z`), digits (`0-9`), `.`, `-`, `_`, and `~`. Note that `:` is not permitted inside the version because it is the separator. Percent-encoding is **not** allowed (atproto record keys reserve but do not currently support `%`). |
There was a problem hiding this comment.
[needs fixing] Line 433 says the version string may include _ and ~ because they are allowed in atproto record keys. Later in the same section the formal grammar forbids them (identifier := [a-zA-Z0-9-]+), and the version field in lexicons/com/emdashcms/experimental/package/release.json explicitly says only ASCII letters, digits, ., and - are allowed because semver disallows _ and ~. This is self-contradictory; the lexicon and grammar are the stricter authority.
| - The portion after `:` MUST equal `version`, byte-for-byte. The version string MUST therefore be composed only of characters allowed in atproto record keys: ASCII letters (`a-zA-Z`), digits (`0-9`), `.`, `-`, `_`, and `~`. Note that `:` is not permitted inside the version because it is the separator. Percent-encoding is **not** allowed (atproto record keys reserve but do not currently support `%`). | |
| - The portion after `:` MUST equal `version`, byte-for-byte. The version string MUST therefore be composed only of characters allowed in this RFC's semver-subset grammar: ASCII letters (`a-zA-Z`), digits (`0-9`), `.`, and `-`. Note that `:` is not permitted inside the version because it is the separator. Percent-encoding is **not** allowed (atproto record keys reserve but do not currently support `%`). |
|
|
||
| The policy is an aggregator operational choice, not a protocol rule — third-party aggregators may set their own. The cap-on-redistribution stance is deliberately conservative to avoid hosting code under licenses that don't permit it, and to leave space for the future paid/private plugin work (FAIR's `auth` field, currently reserved) without baking in a precedent that EmDash mirrors everything. | ||
|
|
||
| **Release response envelope.** When the aggregator returns a release, it wraps the signed record in an envelope with mirror URLs it is currently serving: |
There was a problem hiding this comment.
[suggestion] The "Release response envelope" JSON example shows only { release, mirrors }, but the aggregator releaseView schema in lexicons/com/emdashcms/experimental/aggregator/defs.json returns uri, cid, did, package, version, indexedAt, labels, release, and mirrors. The example is shorthand, but it risks misleading implementers about the actual response shape. Consider updating the example to include the view metadata fields or explicitly noting that the example is truncated.
🚀 Deploying Preview to Cloudflare 🚀Preview URL: https://wip-plugin-rfc.try.emdashcms.com, https://wip-plugin-rfc-emdash-playground.emdash-cms.workers.dev (commit 4397617)This URL reflects your latest Preview deploymentPreview Deployments by commit
|
Draft RFC for decentralised plugin registry.
Rendered markdown: https://github.com/emdash-cms/emdash/blob/wip/plugin-rfc/rfcs/0001-plugin-registry.md
Try this PR
Open a fresh playground →
A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.
Tracks
wip/plugin-rfc. Updated automatically when the playground redeploys.