Two files. No Cargo. No cdylib. No .so to build.
echo-python-source/
├── plugin.toml ← metadata: language, entry_module, node_types, requires
└── echo_python.py ← the actual node implementation
plugin.toml is the standardized metadata file the
RemoteMedia SDK resolver
fetches first when resolving a plugin spec. When language = "python"
is set, the resolver:
- Downloads the repo tarball (for GitHub specs) OR uses the local dir directly (for path specs).
- Provisions a uv-managed venv from
[python].requires. - Spawns
python -m remotemedia.core.multiprocessing.runnerwith--module-root <extracted_dir> --register-module <entry_module>. - Registers each
node_typesentry into the executor's registry.
Same iceoryx2 IPC + READY handshake as the cdylib (Path 4) authoring
flow. Per-plugin venv isolation means deps in requires don't pollute
the host's Python environment.
Reference this repo as a canonical-org shorthand from your pipeline manifest:
{
"version": "v1",
"metadata": { "name": "source-plugin-smoke" },
"plugins": [
"echo-python-source@v0.1.0"
],
"nodes": [
{ "id": "echo", "node_type": "EchoPythonNode", "params": {} }
],
"connections": []
}Then use the standard FFI flow from your consumer process:
import remotemedia.runtime as rt
sess = await rt.create_streaming_session(open("manifest.json").read())
await sess.send_input({"type": "text", "data": "hi"})
print(await sess.recv_data()) # → "echo: hi"
await sess.close()The resolver fetches plugin.toml from
https://raw.githubusercontent.com/RemoteMedia-SDK/echo-python-source/v0.1.0/plugin.toml
and the source tarball from
https://codeload.github.com/RemoteMedia-SDK/echo-python-source/tar.gz/refs/tags/v0.1.0.
git clone https://github.com/RemoteMedia-SDK/echo-python-source
cd echo-python-source
./run.sh # uses ./manifest.json which references "." as the plugin pathThe bundled manifest.json references the plugin as a local path
("."), so the resolver short-circuits the GitHub fetch and uses the
checked-out source directly.
Same shape — just git push + tag a release.
{
"plugins": [
"RemoteMedia-SDK/your-plugin-name@v0.1.0"
]
}No CI matrix needed (no per-platform binaries to build — Python source is portable). For the cdylib-distribution alternative see RemoteMedia-SDK/echo-python-loadable (same node, shipped as Path 4 — embedded Python inside a Rust cdylib).
| Aspect | echo-python-loadable (cdylib) |
echo-python-source (this repo) |
|---|---|---|
| Languages plugin author writes | Rust + Python | Python only |
| Build step | cargo build per platform |
None |
| Distribution | .so / .dylib / .dll (matrix per OS+arch) |
git tag |
| Source visible to consumer | No (embedded in binary) | Yes (cloned) |
| Self-update on commit | Re-publish + re-resolve | Re-resolve same tag → re-fetch |
| First-load time | Fast (dlopen) | Slower (tarball download + extract + venv) |
| Per-plugin venv | Yes (via uv) | Yes (via uv) |
| Aux-port + multi-output support | Yes | Yes (same IPC layer) |
The python_plugin_export! cdylib path stays useful when you want a
sealed binary distribution (vendored sub-package, no source visible to
the consumer). For Python plugins where the source is fine to be public
— which is most of them — this path is dramatically simpler.
- matbeedotcom/remotemedia-sdk — the SDK that consumes this plugin
- RemoteMedia-SDK/echo-python-loadable — same node as a Path 4 cdylib
- Resolver source — dispatch state machine
plugin.tomlschema — full field documentationSourcePythonFactory— the adapter that spawns the Python runner against extracted source