Migrated from FUTURE-NO-MICROSERVER.md (repo root), written 2026-07-26,
before the frontend rebuild. File references in the original doc were
already stale by the time it was written down (swift/public/js/lib.js
-> shapes.js/main.js; next-swift/server.ts no longer exists,
next-swift/+swift/out/ were removed entirely) -- but the architectural
direction below still applies and hasn't been implemented.
SwiftRoute.py still has the /retrieve/ passthrough this proposes
removing. See also #86 (JupyterLite/Pyodide transport) -- the
WebSocketTransport seam built during the rebuild is a narrower,
comms-only piece of this same underlying problem (assets, not just
messages).
Goal
Replace local /retrieve/... file access with standard HTTPS asset
delivery, while preserving: normal desktop Python usage; notebook
embedding (browser="notebook"); practical support for Jupyter and
JupyterLite display workflows.
Current state
start_servers() spins up a WebSocket service and a local HTTP server
serving the UI + a /retrieve/... route that reads an arbitrary local
filesystem path and serves it back. Notebook mode embeds a local URL in
an IFrame. Scene object loading (ColladaLoader/STLLoader/
OBJLoader/etc.) consumes ob.filename values as URLs -- currently
always local.
Architecture direction
Adopt an explicit Asset URL strategy:
- viewer UI served from a web origin (or local dev during development
only);
- mesh/texture assets fetched by normal HTTPS URLs;
- no direct filesystem reads through
/retrieve routes;
- Python emits resolvable URLs (or URL templates), not local file paths.
Suggested API shape: asset_mode: "local" | "remote" | "auto",
asset_base_url (e.g. https://assets.example.com/swift-assets/),
optional asset_url_resolver(path) -> str callback override. Pass
through URLs unchanged; convert local/relative paths under
asset_base_url when asset_mode=remote; keep legacy behavior for
asset_mode=local.
Phased plan (originally sketched)
- Discovery: inventory every place
ob.filename is produced,
classify (absolute local / relative package / already-remote), build
a compatibility matrix (desktop+browser, Jupyter local, JupyterHub
remote, JupyterLite/Pyodide).
- URL resolution layer (Python): central resolver utility per the
API shape above, with unit tests (local path, remote passthrough,
Windows path normalization, URL escaping).
- Frontend hardening: ensure all loaders accept remote URLs as-is,
remove local-path-specific mutations, surface loader errors with the
attempted URL + HTTP status.
- Remove
/retrieve: delete the passthrough branch from
SwiftRoute.py; keep static UI serving for local-only mode if still
wanted.
- Server-side asset hosting: stable URL prefix (e.g.
/swift-assets/), deterministic paths, immutable cache policy,
correct content-types per format, version/hash in path to avoid
stale-cache collisions.
- Jupyter/JupyterLite display strategy: explicit
ui_url/ws_url/
rtc_url/asset_base_url options for hosted notebook mode.
JupyterLite specifically has no local CPython server process
available at all -- initial target should be a display-only
playback mode (precomputed trajectory/events JSON, animate from
static data, no live control loop), with full interactive mode via a
remote WS backend as a later option.
CORS implications by hosting target
- GitHub-hosted (Pages / raw.githubusercontent.com / release
assets): limited per-path header control, especially on Pages --
prefer same-origin viewer+assets where possible; front with a
CDN/proxy if cross-origin header tuning is unavoidable.
- Other managed hosting (e.g. Apache/Nginx): explicit
Access-Control-Allow-Origin/-Methods/-Headers/-Expose-Headers
config available via server config or .htaccess; use an explicit
allow-list rather than wildcard for stricter security postures. If
the WebSocket endpoint is also hosted there: TLS (wss://), reverse
proxy upgrade headers, origin checks at the WS server layer.
Security requirements
- Remove filesystem passthrough serving entirely.
- Enforce HTTPS URLs for remote mode.
- Optional allow-list for asset host domains.
- Clear logs for denied/invalid asset URLs.
Testing plan (sketch)
- Unit: URL resolver (local->remote, HTTPS passthrough, Windows path
normalization, escaping).
- Integration: viewer with remote asset URLs loads meshes correctly; no
/retrieve path required; Jupyter embed smoke test (iframe loads, a
robot + a shape appear, stepping updates pose); negative test for a
disallowed origin / missing CORS header producing a clear surfaced
error.
- Manual matrix: local desktop + local browser; JupyterLab local;
JupyterHub remote; JupyterLite static demo playback.
Rollout strategy
Add the resolver behind opt-in flags -> ship dual mode (local +
remote) for one release cycle -> gather feedback, fix notebook/cloud
edge cases -> deprecate /retrieve with a warning -> remove /retrieve
and local filesystem access in a later minor/major release.
Open questions (unresolved)
- Where should canonical asset hosting live long-term (GitHub+CDN vs.
another managed host)?
- Do we require fully offline local mode forever, or can it become
optional?
- Should remote asset URLs be generated by Swift only, or pre-baked by
upstream model packages?
- Is live interactive JupyterLite a requirement, or is display-only
acceptable for a first release?
Definition of done
- No runtime reliance on
/retrieve in the production path.
- Remote HTTPS assets load in browser, notebook, and hosted notebook
contexts.
- CORS behavior documented and tested for chosen host target(s).
- Jupyter display works with hosted UI/assets.
- JupyterLite has at least one supported display mode with documented
limitations.
Likely files to touch
src/swift/Swift.py -- public launch/config API for asset hosting
mode and URL options.
src/swift/SwiftRoute.py -- remove /retrieve passthrough; support
notebook mode with externally hosted ui_url and explicit WS/RTC
URLs.
src/swift/public/js/shapes.js -- ensure loaders use the provided URL
as-is; improve error callbacks/logging for failed fetches.
tests/ -- resolver unit tests, no-/retrieve integration tests,
notebook-oriented smoke tests where feasible.
README.md / docs -- hosted-asset deployment docs, CORS expectations,
notebook/JupyterLite supported modes.
examples/ -- a hosted-assets example, a JupyterLite-compatible
display-only playback example.
Migrated from
FUTURE-NO-MICROSERVER.md(repo root), written 2026-07-26,before the frontend rebuild. File references in the original doc were
already stale by the time it was written down (
swift/public/js/lib.js->
shapes.js/main.js;next-swift/server.tsno longer exists,next-swift/+swift/out/were removed entirely) -- but the architecturaldirection below still applies and hasn't been implemented.
SwiftRoute.pystill has the/retrieve/passthrough this proposesremoving. See also #86 (JupyterLite/Pyodide transport) -- the
WebSocketTransportseam built during the rebuild is a narrower,comms-only piece of this same underlying problem (assets, not just
messages).
Goal
Replace local
/retrieve/...file access with standard HTTPS assetdelivery, while preserving: normal desktop Python usage; notebook
embedding (
browser="notebook"); practical support for Jupyter andJupyterLite display workflows.
Current state
start_servers()spins up a WebSocket service and a local HTTP serverserving the UI + a
/retrieve/...route that reads an arbitrary localfilesystem path and serves it back. Notebook mode embeds a local URL in
an
IFrame. Scene object loading (ColladaLoader/STLLoader/OBJLoader/etc.) consumesob.filenamevalues as URLs -- currentlyalways local.
Architecture direction
Adopt an explicit Asset URL strategy:
only);
/retrieveroutes;Suggested API shape:
asset_mode: "local" | "remote" | "auto",asset_base_url(e.g.https://assets.example.com/swift-assets/),optional
asset_url_resolver(path) -> strcallback override. Passthrough URLs unchanged; convert local/relative paths under
asset_base_urlwhenasset_mode=remote; keep legacy behavior forasset_mode=local.Phased plan (originally sketched)
ob.filenameis produced,classify (absolute local / relative package / already-remote), build
a compatibility matrix (desktop+browser, Jupyter local, JupyterHub
remote, JupyterLite/Pyodide).
API shape above, with unit tests (local path, remote passthrough,
Windows path normalization, URL escaping).
remove local-path-specific mutations, surface loader errors with the
attempted URL + HTTP status.
/retrieve: delete the passthrough branch fromSwiftRoute.py; keep static UI serving for local-only mode if stillwanted.
/swift-assets/), deterministic paths, immutable cache policy,correct content-types per format, version/hash in path to avoid
stale-cache collisions.
ui_url/ws_url/rtc_url/asset_base_urloptions for hosted notebook mode.JupyterLite specifically has no local CPython server process
available at all -- initial target should be a display-only
playback mode (precomputed trajectory/events JSON, animate from
static data, no live control loop), with full interactive mode via a
remote WS backend as a later option.
CORS implications by hosting target
assets): limited per-path header control, especially on Pages --
prefer same-origin viewer+assets where possible; front with a
CDN/proxy if cross-origin header tuning is unavoidable.
Access-Control-Allow-Origin/-Methods/-Headers/-Expose-Headersconfig available via server config or
.htaccess; use an explicitallow-list rather than wildcard for stricter security postures. If
the WebSocket endpoint is also hosted there: TLS (
wss://), reverseproxy upgrade headers, origin checks at the WS server layer.
Security requirements
Testing plan (sketch)
normalization, escaping).
/retrievepath required; Jupyter embed smoke test (iframe loads, arobot + a shape appear, stepping updates pose); negative test for a
disallowed origin / missing CORS header producing a clear surfaced
error.
JupyterHub remote; JupyterLite static demo playback.
Rollout strategy
Add the resolver behind opt-in flags -> ship dual mode (
local+remote) for one release cycle -> gather feedback, fix notebook/cloudedge cases -> deprecate
/retrievewith a warning -> remove/retrieveand local filesystem access in a later minor/major release.
Open questions (unresolved)
another managed host)?
optional?
upstream model packages?
acceptable for a first release?
Definition of done
/retrievein the production path.contexts.
limitations.
Likely files to touch
src/swift/Swift.py-- public launch/config API for asset hostingmode and URL options.
src/swift/SwiftRoute.py-- remove/retrievepassthrough; supportnotebook mode with externally hosted
ui_urland explicit WS/RTCURLs.
src/swift/public/js/shapes.js-- ensure loaders use the provided URLas-is; improve error callbacks/logging for failed fetches.
tests/-- resolver unit tests, no-/retrieveintegration tests,notebook-oriented smoke tests where feasible.
README.md/ docs -- hosted-asset deployment docs, CORS expectations,notebook/JupyterLite supported modes.
examples/-- a hosted-assets example, a JupyterLite-compatibledisplay-only playback example.