Support invocation-scoped async native filesystem providers for managed Python Dynamic Workers
Request
Please identify an existing supported integration hook, including its compatibility/runtime version, or provide an opt-in, runtime-owned asynchronous native filesystem provider for managed Python Dynamic Workers. The authoritative provider should be an explicitly selected service binding; ordinary native Python operations must await that provider without copying a workspace into/out of the child's memory filesystem.
This is a capability request, not a claim that managed integration is inherently impossible. An application-provided static Pyodide/JSPI interpreter is a separate working option, but does not qualify Cloudflare's managed Python interpreter.
Use case and required behavior
A JavaScript Worker loads a managed Python child with env.LOADER.load(), forwards an explicit filesystem service binding, and disables implicit outbound access. Explicit asynchronous RPC to that service works, but does not automatically mount it beneath Python's native file operations.
For a provider containing a public test file /work/canonical_module.py with answer = 42, the same authoritative filesystem should support, during an initialized managed invocation:
import importlib
import os
import sys
metadata = os.stat('/work/canonical_module.py')
with open('/work/canonical_module.py', 'rb') as source:
contents = source.read()
sys.path.insert(0, '/work')
module = importlib.import_module('canonical_module')
assert module.answer == 42The desired mechanism must cover the native syscall/import paths, not only replacement Python builtins. Returning a Promise from a synchronous Emscripten filesystem callback is not a suspension contract. None of this requires general network access, arbitrary native processes, or arbitrary native-module compilation privileges.
Pinned current primary-source boundary
Reviewed current workerd main: 266d066e8bd1962e2e02cedd9718252f44aa1217 (September 18, 2026). These observations are scoped to the reviewed public interfaces:
WorkerLoader::WorkerCodeenumerates the public loader configuration. It admits modules, explicit environment/service bindings, and outbound policy, but no native-filesystem provider or pre-instantiation hook.getInstantiateWasmowns the import object beforeWebAssembly.instantiate.instantiateEmscriptenModulereceives the stdlib and compiled main Wasm module, not an application provider/settings argument. This is a concrete runtime-owned insertion point, not an available application API.loadPyodideinstantiates before exposing the public API and mounts application files after baseline snapshot collection.compileModuleFromReadOnlyFSpreserves trusted read-only native-library admission. Both boundaries must remain intact.WorkerLoader::extractSourcerejects Python modules beneath a JavaScript main, so a JavaScript-first application bootstrap is not an existing public way to configure the managed interpreter's imports.WorkerStubexposes entrypoint/class access rather than an explicit awaited interpreter-retirement surface. This does not assert that internal cancellation or cleanup is absent; a supported invocation protocol may satisfy the requirement without a new general disposal method.
Proposed minimum supported capability
Field names and protocol shape need maintainer agreement; these are requirements, not claims about an available SDK API.
- Trusted provider selection: a versioned service-binding capability selected by the loader owner, with explicit namespace/cwd and descriptor/transfer budgets. Native pointers stay within the managed interpreter; RPC transfers bounded logical operands and owned bytes.
- Runtime-owned native dispatch: install suspension-capable syscall/import dispatch before main Wasm instantiation, or document an equivalent supported native boundary outside synchronous JavaScript filesystem callback frames. Include stat/fstat, open/read/write/seek, directories, mutations, synchronization, descriptor duplication/close, source/ZIP imports, native-extension I/O and binary fd 0/1/2. Preserve each operation's native errno/errors and descriptor identity; no optimistic close or deferred error masquerading as success.
- Snapshot-safe activation: attach application capabilities after managed bootstrap/baseline restoration. Do not capture application bindings, open descriptors, pending work or cancellation in baseline snapshots. Preserve authenticated runtime packages and trusted native-library admission.
- Awaited invocation cleanup: while the invocation I/O context remains valid, stop admission, cancel/drain owned tasks, finalize guest buffers/destructors/exit handlers as applicable, await descriptor closure, and detach callbacks before interpreter retirement. Specify runtime-versus-adapter ownership. Late completions must not access retired memory, and closing one invocation must not cancel siblings or retire a borrowed provider.
- Backpressure/cancellation: await bounded binary I/O and writes, propagate cancellation to admitted backend work, and retain cleanup failures. Cancellation cannot undo completed effects or preempt arbitrary CPU-only code. This request does not imply guest confinement.
A fresh managed child with one admitted invocation is sufficient for an initial capability. Concurrent calls sharing one interpreter are not required.
Minimal public evidence and qualification gates
The public downstream tracking issue is poe-platform/poe-code#746. Public npm @poe-platform/safe-bash, safe-fs, and safe-js 0.1.684 provide an independent static JSPI reference using Pyodide 314.0.6:
- Maintained public-package native/lifecycle fixture.
- Actual official Cloudflare Playground preview qualification: all eight unchanged native I/O/import/binary/lifecycle/cancellation/ownership workloads passed with authenticated static assets, then the preview was replaced and verified HTTP 410. This proves the independent custom option on the Cloudflare network, not a managed canonical filesystem mount or an account-owned deployment.
For the managed capability, first qualify native stat/import/descriptor lifecycle against a delayed authoritative provider, including a native caller that does not depend on CPython retry behavior. Then cover exact backend errors, small transfer/descriptor budgets, C-extension and binary stdio paths, async finalization, startup/in-flight cancellation, cleanup failures, late completion and sibling ownership. Finally run the installed-public-package managed consumer and an authorized disposable deployment on the supported runtime version.
Before filing, I searched existing workerd issues for Python/Pyodide filesystem, Python JSPI/mount, preinstantiation/pre-instantiation, filesystem provider and native filesystem. I found no equivalent managed-provider request; the provider search's unrelated RPC typing issue #3063 is not a duplicate.
Maintainer question: is there a supported hook satisfying these native dispatch and awaited lifecycle requirements today? If not, is a versioned runtime-owned provider capability at the identified instantiation/lifecycle boundaries an acceptable upstream direction, and who should own its interface and runtime tests?
Source: cloudflare/workerd