Service-per-origin cutover: delete /service/ proxy, apps own their origins - #342
Open
amirmohsen-am wants to merge 4 commits into
Open
Service-per-origin cutover: delete /service/ proxy, apps own their origins#342amirmohsen-am wants to merge 4 commits into
amirmohsen-am wants to merge 4 commits into
Conversation
…ename system-interface Every registered service owns a browser origin (local: <name>.agent-<hex>.localhost; shared: <name>--<host>--<user>.<domain>). The system_interface proxy/service_dispatcher and all four transforms are deleted; the frontend derives service origins from location.host at render time (layouts persist serviceName, not origins); browser-fleet API calls go through a same-origin /api/browsers passthrough; forward_port validates DNS-safe names; the supervisord service is renamed system-interface; docs and skills describe the own-origin model. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The browser service's docstrings still described the deleted /service/ proxy and the removed ROOT_PATH env (now-dead read dropped). Layout URL parsers now require both '--' separators of a share hostname so an external panel host that merely contains '--' can't masquerade as a service (with regression tests). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…erviceUrl - The two Python copies of the origin->service-name parse (layout_ops.py and the stdlib-only scripts/layout.py, which cannot import the package) now cross-reference each other and are pinned by a drift test in layout_ops_test.py. - layout.py's _service_name_from_ref delegates to _service_ref_parts instead of re-implementing the ref grammar scan. - preview_wrapper_server's inline sibling-origin JS cites origin.ts as the owner of the origin scheme. - getServiceUrl was a bare alias of deriveServiceOrigin; inlined at its six call sites. - The build-app scaffold now reserves "localhost" (forward_port.py rejects it at registration, so the scaffold could mint an unregistrable app) and a drift test asserts scaffold-accepted names stay a subset of forward_port's registration rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
amirmohsen-am
commented
Jul 28, 2026
Comment on lines
+21
to
+34
| export function deriveServiceOrigin( | ||
| serviceName: string, | ||
| host: string = window.location.host, | ||
| protocol: string = window.location.protocol, | ||
| ): string { | ||
| // Shared (Cloudflare) hosts are ``<name>--<host>--<user>.<domain>``: the | ||
| // sibling service's hostname swaps the text before the first ``--``. | ||
| if (host.includes("--")) { | ||
| return `${protocol}//${serviceName}${host.substring(host.indexOf("--"))}/`; | ||
| } | ||
| // Local workspace hosts (``agent-<hex>.localhost[:port]``) nest the | ||
| // service as a subdomain label. | ||
| return `${protocol}//${serviceName}.${host}/`; | ||
| } |
Author
There was a problem hiding this comment.
This can be brittle to determine if host is Cloudflare only by if (host.includes("--")) but we can bundle the change when updating remote_service_connector and include the origin in the http headers from cloudflare to make it cleaner
The rename existed only for DNS-label hygiene, but underscore hostname labels work everywhere this scheme needs them: Cloudflare DNS minted system_interface--<host>--<user> share hostnames before this redesign, Chromium/Electron accept underscore hostnames, and the forwarder's SNI cert minting + strict hostname verification pass for system_interface.agent-<hex>.localhost. Keeping the name avoids breaking resumed snapshots whose apps.toml predates the PR and shrinks the diff (supervisord, oom bands, recovery probe, docs all revert). forward_port.py's registration rule now allows underscores (consecutive hyphens stay rejected -- '--' is the share-hostname separator); the build-app scaffold stays kebab-only for new apps, still a strict subset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Service-per-origin cutover: delete the /service/ proxy, own-origin apps
Template side of the forwarding redesign (
blueprint/forwarding-redesign/plan-forwarding-redesign.mdin mngr; pairs with the mngr PR on the same branch name). Every registered service now owns a real browser origin; nothing proxies or rewrites app traffic anymore.Deleted
system_interfaceproxy stack:proxy.py,service_dispatcher.py, their tests, and theregister_service_routeswiring — service-worker bootstrap, HTML/<base>rewriting, WS shim, cookie-path rewriting are all gone.Changed
location.hostat render time (src/origin.ts): local hosts prefix the service label (http://<name>.agent-<hex>.localhost:8421/), shared hosts swap the first--token (https://<name>--<host>--<user>.<domain>/). Layouts persistserviceName, never origins — portable across hosts and shares.GET/POST /api/browsers) instead of the deleted proxy path.forward_port.pyvalidates DNS-safe service names (lowercase alnum + single hyphens; no underscores; noagent-prefix; notlocalhost) with a new test suite.system_interface→system-interface(DNS-safe); oom-priority band, docs, and the deadROOT_PATH=/service/browserenv updated/removed.layout.py/layout_ops.pyspeak service coordinates instead of/service/paths. A panel's real URL now depends on the viewer's host (local vs share), which server-side code can't know — so it refers to panels asservice:<name>[?query]and the frontend resolves that to a real origin at render time. When these scripts read URLs back out of persisted layout state, they extract the service name from the hostname (handles both the local and shared host shapes, with a guard so external hosts containing--aren't mistaken for services).Validation
Frontend build/lint/vitest green; root pytest and system_interface pytest green (remaining failures verified pre-existing/environmental). Real-workspace e2e (local + Cloudflare share, including agent-installed openvscode with its own service worker and webviews) documented in the mngr repo at
blueprint/forwarding-redesign/validation-results.md.Future TODO
npm run buildruns in CI).--webview-external-endpoint={{uuid}}.<name>.<workspace-host>) once shared wildcard certs land connector-side.🤖 Generated with Claude Code