RFC: Frontend Contribution Layer — plugins that ship UI (dashboard · auth · ai · deploy)#890
Draft
rickylabs wants to merge 11 commits into
Draft
RFC: Frontend Contribution Layer — plugins that ship UI (dashboard · auth · ai · deploy)#890rickylabs wants to merge 11 commits into
rickylabs wants to merge 11 commits into
Conversation
… (generator stage) Research corpus, locked design (contracts/DX/discovery/host-runtime/scaffolding/doctrine), four worked consumer examples (dashboard, auth, ai, deploy), plan with owner forks F1-F8. Drafts only; STAGE-COMPLETE: generator — Sol adversarial + Kimi docs passes are supervisor-dispatched next. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
…ll 20 accepted) Envelope+family versioning, identity quartet, context split, HostSurfaceDescriptor, literal route loaders + post-fsRoutes composition, islands proof-gated, honest SSR containment, deny-by-default procedure gateway, transactional emissions, corrected consumer examples, Wave-0 five-proof phasing, fork re-triage. Triage dispositions in adversarial-triage.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
…ll 17 accepted) FrontendDefinition named + contract default + MessageRef string shorthand + theme singular; PluginPageContext + redirect; pluginApi(client) and GATEWAY_PREFIX pinned; pointer de-duplicated; ModuleRef rename; budgets + defineFrontendTestSuite; route-param cross-check; doctor taxonomy as product surface; examples re-aligned to rev-2 shapes. Dispositions in docs-story-triage.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
…raft-PR deliverable) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
This was referenced Jul 19, 2026
This was referenced Jul 19, 2026
Owner
Author
|
[PHASE: PLAN] [BOARD: FILED] Board filed 2026-07-19 under in-turn owner authorization (milestone fit + new-milestone authority delegated; deploy-lane split used as precedent). Filed
Next
Full mapping: |
…(FILING-LOG, labels.yml parity, authority banner) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
Owner
Author
|
[BOARD ADDENDUM] Owner re-scheduling (2026-07-19): no Backlog items on this epic — milestone |
…laces Backlog placements Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RFC — NetScript Frontend Contribution Layer: plugins that ship UI
FILING-LOG.md, this PR) · sibling RFC: deploy-plugin #891 (epic #892).llm/runs/plan-frontend-contrib--seed/— research, plan (D1–D16 / forks), canonical design 00–06, 4 worked examples, docs-story forecast, both review-triage records; canonical RFC text:rfc.md(this PR)App.mountApp(@fresh/core 2.3.3 app.ts:357),Builder.registerIsland(dev/builder.ts:157),fresh({ islandSpecifiers })(@fresh/plugin-vite 1.0.8 mod.ts:211-214); repo precedent: axis registry emitter,scaffolder.exportpointer, fresh-ui copy-registry +--ns-*tokens, ai chat-route scaffolder; prior art: the beta-10 dashboard extension architectureAbstract
Today a NetScript plugin contributes services, workers, schemas, streams, migrations, and Aspire wiring — but not one pixel of frontend. There is no
.tsxunderplugins/, the scaffolded app's nav is a hardcoded array, and four announced features are blocked on the same missing axis: the dev dashboard (plugin panels), auth (sign-in, session, org UI), ai (chat and distributed assist surfaces), and the new deploy plugin (cloud consoles + cloud-first scaffold seams).This RFC makes a plugin a full-stack unit:
Contributions are data (schema-first contracts in
@netscript/plugin-frontend-core), discovered like every existing axis (manifest pointer + generated, type-checked registry in.netscript/generated/), and mounted through thin wrappers over upstream Fresh 2.3 primitives that already exist. Two delivery models are first-class: live (package-served, versioned — consoles, panels, widgets) and scaffolded starter (app-owned, customizable — sign-in pages, cloud-first seams). The dev dashboard's ratified 7-kind contribution family becomes a sibling payload family on the same envelope — one discovery pipeline, many hosts.1. Motivation
PluginContributions;PluginType 'frontend'is an inert enumislands/dirchat.tsxinto the appThe blocked consumers are not hypothetical: auth has a complete oRPC surface (
signin/callback/signout/session/me) with zero UI; ai has a durable-chat runtime plane (@netscript/fresh/ai) with only a scaffold-time stub; the deploy redirect explicitly demands "contribute to every layer (even frontend soon)"; the dashboard epic (#400, beta.13) needs the seam this RFC generalizes.2. The proposed decision and its rationale
Decision (D1–D16, locked at generator level and twice-reviewed):
@netscript/plugin-frontend-coreholds serializable types + schemas only (no fresh/preact deps); all runtime helpers live in@netscript/fresh/plugins. Why: keeps the registry statically emittable and the contracts JSR-clean (adversarial finding S-5).FrontendManifestEnvelopecarries(family, major)-versioned payloads; theappfamily v1 has five kinds (route / island / zone / nav / theme); the dashboard family is a sibling payload, not a widened union. Why: adding union members breaks strict old validators — the naive "additive union" was disproved in review (S-7).@netscript/pluginlearns only.withFrontend({ export, framework }); the handshake is derived from the module at generate time. Why: resolves the long-open OQ-12 thinness tension with zero core vocabulary and no dual source of truth.netscript generate pluginsemits a transactional replace-set (frontend.registry.ts,frontend.islands.ts,frontend.routes.ts,frontend.css,frontend.gateway.ts,frontend.check.ts) — staged, type-checked (the check module imports every referenced module), atomically swapped; deterministic empty emissions make removal clean.App.mountAppin a post-fsRoutes composition phase with generated literal loaders + a route-module normalizer; islands register by module specifier on both build paths; nav feeds the existingSidebarShellmodel; theming is--ns-*tokens under a host-owned CSS layer order. The ordering/normalization subtleties were review findings (S-1, S-2) and are Wave-0 proofs before contracts freeze.requires.procedures× the plugin's contract metadata — no wildcard forwarding, server-side auth, no blind credential forwarding, streaming only where declared. Why: a generic forwarding proxy is a confused-deputy surface (S-6).AppTargetonScaffolderContext); if the plugin owns it, serve it live. Starters never fabricate backend surface.onError; SSR render throws are documented page failures, not false "isolation" (S-4). Dashboard T1/T2 iframe tiers remain the dashboard epic's scope.defineFrontend, ordinary Fresh files, string label shorthands, contract defaulting, tooling-owned export maps,netscript plugin dev— fixed first and defended through both review passes; a docs-forecast stage wrote the public guide + references against the API and its 17 findings were folded back in.3. Public API design (implementation-level)
What a plugin author writes
Pages/islands are ordinary Fresh modules; islands are imported and rendered directly (the build registers their specifiers);
definePluginPage(from@netscript/fresh/plugins) typesctx.host/ctx.client/ctx.redirect;pluginApi(ctx.client)returns the plugin's gateway base (/api/plugins/<mountId>— a pinned contract constant).Contract surface (
@netscript/plugin-frontend-core/contracts/v1)FrontendManifestEnvelope{ contract: FamilyRef, pluginKind, base?, contributions, requires?, budgets? }; multi-family = an array of envelopes.appfamily kinds:RouteContribution(literal-loader mounted,_layoutrejected v1),IslandContribution(serializable-props law),ZoneContribution,NavContribution(discriminatedroute/href/externaltargets, MessageRef labels),ThemeContribution(one per plugin,--ns-*only).packageName/pluginKind/installationId/mountId— all generated keys (base path, CSS scope, gateway prefix, route-ref namespace) derive frommountId.HostSurfaceDescriptor: hosts publish zones, nav groups, reserved paths, and supported(family, major)windows; diagnoses distinguish unknown zone (error) vs known-but-unmounted (info) vs capacity-rejected vs quarantine (window mismatch / load failure).PluginRequestContext(serviceUrl, principal port, CSP nonce, abort) vs serializablePluginClientContext(locale/direction/timeZone, subject summary, capabilities) — the island boundary is typed, not folklore../testing:defineFrontendTestSuite(manifest, options)— schema, props round-trip, SSR, hydration, browser smoke, a11y, base-path, local+JSR modes; asserts the envelope'sbudgets.Host wiring (scaffolded by default)
CLI:
plugin install/update/removeregenerate transactionally;plugin new --with frontendscaffolds the tree + exports;netscript plugin devowns the watch/regenerate/reload loop;plugin doctorprints the five-state diagnosis taxonomy;plugin resource add <plugin> <resource> --app <path>lands app-owned starters;generate frontend-wiringadopts existing apps idempotently.Consumers (worked examples in the run dir)
/dashboardnow; the dashboard host later consumes the same registry under/plugins/<mountId>with its own family/auth/account+ topbar session widget over the real 5 procedures; starter: sign-in/callback pages; org console gated on a namedauth-orgbackend capability (does not exist yet — no invented APIs)4. Plan — waves and gates
Wave 0 — five disposable proofs before any contract freezes: P1 mount ordering/layout/basePath · P2 literal loaders + route normalization · P3 dependency-island matrix (clean cache × local/JSR × dev/prod, Preact identity, CSS, edit loop) · P4 SSR containment fixtures · P5 gateway threat model + stream abort.
Wave 1 — contracts + spine (envelope/schemas, identity, transactional emissions +
frontend.check.ts, mount glue, host descriptor, scaffold wiring, workers dogfood). Wave 1b — the gateway (own reviewed wave). Wave 2 — DX + lifecycle (plugin new/dev, doctor taxonomy, quarantine states, AppTarget starters, test kit + budgets, adoption verb). Wave 3 — consumers (auth v1, ai chat, remaining panels; dashboard + deploy epics consume the layer in their own runs).Gates: per-archetype F-* columns + SCOPE-frontend browser gates;
quality:scan+arch:checkon everypackages/**/plugins/**slice; the per-plugin test kit; extendedscaffold.runtime(install → render → hydrate → remove) at merge-readiness.5. Board — FILED 2026-07-19 (owner-authorized). Epic #922; FCB-n → #923–#946 per
FILING-LOG.md; GitHub wins on conflict. Original proposal below:Epic FCL-EPIC —
Epic: Frontend contribution layer·type:umbrella+epic:frontend-contrib+area:fresh/area:plugins· milestone Backlog / Triage (owner schedules later). Children ([frontend-contrib S<n>] …, eachPart of #FCL-EPIC):@netscript/plugin-frontend-corecontracts/v1 (envelope, families, identity, schemas,defineFrontend)@netscript/pluginpointer axis (.withFrontend, manifest block,CONTRIBUTION_AXES)frontend.check.ts+ install/update/remove regeneration@netscript/fresh/plugins: composition phase, mount glue, normalizer,PluginZone, nav feed,definePluginPage/pluginApiHostSurfaceDescriptor+ viteislandSpecifiersfeedplugin new --with frontend·netscript plugin dev· doctorfrontendcheck + taxonomy · quarantine render states ·AppTarget+plugin resource add --app·./testingkit + budgets ·generate frontend-wiringauth-orgbackend capability (org-console prerequisite) · convention generator6. Migration / supersession map (proposed dispositions — no closes in this RFC)
DashboardPanelContributionseam (DDX-17)AppTarget); the dashboard "second caller" story is unchangedplan/deploy-plugin, sibling RFC)defineFrontendconsoles + AppTarget cloud starters; adapter panels dogfood the zone mechanismchat-routescaffoldergenerate frontend-wiring(idempotent opt-in); new scaffolds get it by default7. Security model (summary)
T0 trust on the app surface; the gateway is the only client-reachable data path — deny-by-default generated routes, server-side auth via the principal port, no blind credential forwarding, CSRF/origin checks, limits/timeouts/abort, manual redirects, response-header allowlist, per-invocation audit line;
requiresis the auditable grant surface; CSS confined by layer order +[data-ns-plugin]scoping + per-plugin portal roots; quarantine-not-crash rendering for contract drift; T1/T2 sandbox tiers deferred to the dashboard epic by design.8. Review trail
Three-stage pipeline, generator ≠ reviewer sessions throughout: Stage 2 — GPT-5.6 Sol·high adversarial review, 20 findings (7 blockers), all verified against upstream jsr sources; 20/20 accepted and integrated (
adversarial-sol.md+adversarial-triage.md, this PR). Stage 3 — Kimi K3 docs-forecast (public guide + API references written as-if-shipped), 17 K-notes; 17/17 accepted and integrated (design/docs-story/+docs-story-triage.md, this PR). The Wave-0 proof gates exist because review demanded mechanism proof before contract freeze.9. Open forks for owner arbitration
.withFrontend()pointer in@netscript/plugin(b) manifest-only/plugins/<mountId>/auth/accountbeats/plugins/auth/account; collisions caught deterministically@netscript/plugin-frontend-core(b) fold into@netscript/fresh(c)@netscript/frontend-coreplugin-*-core, fresh-free contractsProvenance. Seed run
plan-frontend-contrib--seed; the canonical RFC text isrfc.mdin this PR, condensing the run's normative record (design/canonical/00–06rev 3,plan.md,design/examples/,design/docs-story/). Where this RFC and the run docs conflict, the run docs win until ratification, then GitHub wins. Refs #427 #432 #400 — no closing keywords; the §5 board is now live (epic #922, children #923–#946); forks §9 remain open for owner arbitration.🤖 Generated with Claude Code
https://claude.ai/code/session_015fc7SaneZJ9mzrAhRW4tma