Repository navigation
docs(rfc): propose plugin hot reload and plugin-defined APIs - #2579
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hidb4ai
left a comment
There was a problem hiding this comment.
The proposed reload and page-isolation mechanisms have reproducible gaps in their stated contracts. Details are inline; please address them in both language versions before accepting the RFC.
…a group Pin every call to a read-only snapshot named by the content digest so a draining host never mixes versions and a failed update keeps the old one, detect changes by content instead of size and mtime, mount plugin routes under their own group with per-route Scope authorization, let plugins create Scopes with core's existing permission, and state page isolation as session isolation, stopping forwarding once the iframe navigates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move scan, host replacement, and hosting page flows and the literal CSP header to the implementation design. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, and record API changes as Sources Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hidb4ai
left a comment
There was a problem hiding this comment.
The content digests and immutable snapshots address the previous reload findings. Explicitly allowing external access also supersedes the original form-submission finding. Two issues remain in the revised design: navigation can expose the authenticated forwarding bridge to an external document, and MCP tool names can collide. Please address both language versions.
| - **Stop forwarding after navigation**: a sandboxed iframe can navigate itself to an external site, which CSP cannot | ||
| prevent. The external page can also send `postMessage` to the hosting page and passes the `event.source` check. The | ||
| hosting page therefore stops forwarding after the iframe's second load, so an external page cannot borrow the user's | ||
| session. Plugin pages should be single-page applications; navigating between plugin pages also stops forwarding. |
There was a problem hiding this comment.
[P1] Bind forwarding to the original document before navigation completes
Waiting for the second iframe load is too late: scripts in the destination document run before that event. In a Chromium fixture implementing this rule, the plugin navigated to another local origin, whose script immediately posted a request for a declared plugin route while a slow image delayed load. The parent accepted it with loads === 1 and event.origin === "null", fetched the route with its HttpOnly; SameSite=Strict session cookie and Sec-Fetch-Site: same-origin, and returned the synthetic private response to the external document before disabling forwarding. The server-side checks therefore do not close this window. Bind requests and replies to a capability or message channel held only by the original document, rather than relying on the second load event and the frame's persistent WindowProxy identity.
| - The tool name is `<plugin name>_<handler>` (with `-` replaced by `_`), and its description comes from `description`, | ||
| which is required when opting in. Tool parameters combine path parameters, query parameters, and `request_model`; the | ||
| parameter named by `scope_param` is the Scope ID. |
There was a problem hiding this comment.
[P2] Make MCP tool identities unambiguous across routes and plugins
The prescribed name is not unique for otherwise valid declarations: plugin docs with handler search_all and plugin docs-search with handler all both become docs_search_all. The same plugin can also expose two distinct (method, path) routes using one handler, which produces the same collision. A tools/call with that name and identical arguments cannot select which route to execute, so at least one opted-in route is unreachable or resolves to the wrong operation. Define collision-free tool identities, or reject duplicate generated names across all active plugin and built-in tools before activation, including during hot reload.
… and change their own Artifacts Implements the Artifact plugin part of RFC oceanbase#2549 and the plugin APIs and Dashboard pages of RFC oceanbase#2579, and replaces the managed Artifact plugin framework (oceanbase#2246). - A plugin is a directory with plugin.py assigning an ArtifactPlugin. Server checks it in a child process; generate runs in Supervisor Workers, and render_artifact, search_artifacts, user changes, Source writes of the plugin's own types, and plugin routes run in a per-plugin host process. - Plugins present (GET .../rendering) and search their own families: generic search passes the complete request to search_artifacts, and Prepared Context sections may list plugin families. Core builds no index for them. - Revision v1_5_0_005 removes the previous framework's storage only when it is empty, adds pc_artifacts.metadata (plugin name and code digest), and accepts plugin: bindings; frozen revision resources are unchanged. Portable revision records move to schema version 3 and still restore version 2. - Plugin APIs mount at /v1/plugins/{name}/api with a configurable body ceiling, and plugin pages run in a sandboxed Dashboard frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RFC oceanbase#2549 renamed the factory to setup and requires render_artifact; standalone Source plugins moved to RFC oceanbase#2617, so the examples declare routes and pages on an Artifact plugin that brings its own Source type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ls without collisions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hidb4ai
left a comment
There was a problem hiding this comment.
Re-reviewed 02089a8. The setup factory rename and ArtifactPlugin example updates leave both previously reported blockers unchanged: navigation can expose authenticated forwarding to an external document and generated MCP tool names can collide. The affected sections are unchanged in both locales, so the existing findings still apply to this head. Please address them in the original threads.
… and change their own Artifacts Implements the Artifact plugin part of RFC oceanbase#2549 and the plugin APIs and Dashboard pages of RFC oceanbase#2579, and replaces the managed Artifact plugin framework (oceanbase#2246). - A plugin is a directory with plugin.py assigning an ArtifactPlugin. Server checks it in a child process; generate runs in Supervisor Workers, and render_artifact, search_artifacts, user changes, Source writes of the plugin's own types, and plugin routes run in a per-plugin host process. - Plugins present (GET .../rendering) and search their own families: generic search passes the complete request to search_artifacts, and Prepared Context sections may list plugin families. Core builds no index for them. - Revision v1_5_0_005 removes the previous framework's storage only when it is empty, adds pc_artifacts.metadata (plugin name and code digest), and accepts plugin: bindings; frozen revision resources are unchanged. Portable revision records move to schema version 3 and still restore version 2. - Plugin APIs mount at /v1/plugins/{name}/api with a configurable body ceiling, and plugin pages run in a sandboxed Dashboard frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Which issue or RFC does this PR close?
This PR proposes a follow-up RFC to RFC #2549 (plugin interfaces). It builds on the plugin host processes and the in-memory record of active plugins defined there. The plugin APIs and Dashboard pages are implemented in #2616.
Rationale for this change
RFC #2549 deliberately leaves out three things:
Shared central deployments need to update plugins without downtime. Domain plugins such as document knowledge bases need their own operations (file upload, chunk editing, cross-base search and question answering) and their own pages, which do not fit core's generic APIs.
What changes are included in this PR?
New RFC
docs/{en,zh}/rfcs/2579-plugin-reload-and-apis.md(Chinese first, English translation in sync):POWERCONTEXT_SERVER_PLUGINS_RESCAN_SECONDS(default 60 s, 0 disables). A directory is checked only after its content digest is the same in two consecutive scans.upgrade(ctx), which core calls each time it loads a plugin version, before the version serves requests. The plugin decides whether and how to upgrade its data and stays compatible with old data itself; core records no data version and gives no fallback. The hook must be safe to repeat and to run on several instances at once./v1/plugins/{name}/api{path}withaccessauthenticated,scope.read, orscope.contribute(withscope_param). Core authenticates the caller; the host process checks Scope access and runs the handler.accessorctx.require, then usectx.reads,ctx.writer,ctx.sources, andctx.scopesas the caller. Writes in plugin APIs record no automatic provenance; to record who did what, a plugin submits the operation as a Source it defines and writes the revision ingenerate.max_body_bytesunder a deployment ceilingPOWERCONTEXT_SERVER_PLUGIN_API_MAX_BODY_BYTES(default 32 MiB) that replaces the general HTTP body limit for plugin routes.mcp=True). Per-plugin OpenAPI is served at/v1/plugins/{name}/openapi.json, outside the main contract.postMessageforwarding by the Dashboard as the signed-in user, and never see the session cookie. Forwarding stops once the frame navigates away.Are there any user-facing changes?
This PR changes documentation only. The proposed design adds plugin API routes, Dashboard plugin pages, MCP tools for opted-in routes, and two environment variables; it changes no existing API.
How was this change tested?
uv run prek run --files docs/en/rfcs/2579-plugin-reload-and-apis.md docs/zh/rfcs/2579-plugin-reload-and-apis.mdAI usage statement
Drafted with Claude Code (Claude Opus 5.5) under the author's direction and review.
🤖 Generated with Claude Code