Python Code Nodes

Here is a runnable python Code node. Press Run in its toolbar — the script executes on a connected Python worker and the output attaches directly below the code:

That is the whole feature. What you just ran is a Code node whose Language is python: print(...) was captured as output, the trailing bare expression became the return value (REPL semantics), and Inputs carried the caller's parameters. A csharp node (the default) runs in-process on the mesh's Roslyn kernel; a foreign-language node is routed over the mesh to a connected worker instead — pythonpy/python-kernel, javascript/typescriptnode/node-kernel (CodeNodeType.ResolveKernelAddress) — the same gRPC bridge that lets any process join the mesh as a participant (see Foreign Language Integration). The worker runs the script and writes the result back onto the same Activity node every subscriber already watches, so a python or js/ts run surfaces output identically to a C# one. With no worker connected the run reports that in the same output pane — nothing hangs.

Inside the node

The node above is nothing more than a CodeConfiguration with Language = "python" and IsExecutable = true:

{
  "id": "SampleStatistics",
  "namespace": "Doc/Architecture/PythonCodeNodes",
  "name": "Sample statistics (Python)",
  "nodeType": "Code",
  "content": {
    "$type": "CodeConfiguration",
    "code": "import statistics\n…",
    "language": "python",
    "isExecutable": true
  }
}

Create your own through the Code editor (pick python in the language selector), over MCP, or the SDK — then press Run. Any exception is captured and reported as a failed run; the worker never wedges on a bad snippet.

The flow

 Run a Code node (Language = "python")
        │  ExecuteScriptRequest
        ▼
 CodeNodeType.HandleExecuteScript ──creates──► ActivityLog node  (Status = Running)
        │  SubmitCodeRequest { Language = "python", ActivityLogPath }
        │  (C# would go in-process to the Roslyn kernel; python is re-targeted)
        ▼
   py/python-kernel  (a connected Python worker — clients/python)
        │  execute_python(code, Inputs): stdout + trailing-expression value
        ▼
   patch the ActivityLog node  (Status = Succeeded/Failed, messages, returnValue)
        │
        ▼
   every subscriber (the Code node's Output pane, the activity feed, tests) sees it

The only .NET-side change relative to C# is where the submission is sentCodeNodeType.ResolveKernelAddress(language, activityPath) picks the target: pythonpy/python-kernel, javascript/typescriptnode/node-kernel (the Node worker, clients/typescript), everything else in-process. Each worker executes and patches the same ActivityLog, so js/ts output surfaces exactly like python and C#. The concurrency-critical Roslyn KernelExecutor is untouched — it only ever runs C#.

Run a language worker

The worker lives in the Python SDK (clients/python). It connects as a stable participant address so the kernel can target it:

cd clients/python
pip install -e .
bash scripts/gen_proto.sh                      # generate gRPC stubs from the canonical mesh.proto
python -m meshweaver.worker \
    --url https://memex.meshweaver.cloud \
    --token mw_…                                # validated server-side; the worker writes under this identity
    --address py/python-kernel                 # the address CodeNodeType routes python submissions to

It registers under py/python-kernel, then waits for SubmitCodeRequest deliveries. Each one runs in a fresh namespace.

javascript / typescript — the Node worker is the exact equivalent, from clients/typescript: npm run build && node dist/worker.js --url … --address node/node-kernel. It runs the snippet in a vm sandbox with the same REPL semantics (console.log captured, trailing expression = return value, Inputs global; TypeScript is transpiled first). Same wire contract, same Activity write-back.

Identity / access. The worker writes the Activity node under the identity of its --token. That identity needs write access to where activities are stored (the runner's home partition). Use a token whose user can write there — the same access model as any participant.

Ship it as a trusted sidecar (no token)

The command above is the manual / dev shape. In a deployment the worker ships in the portal's own pod as a sidecar and connects to the portal's trusted loopback gRPC endpoint instead of an external URL:

# built from deploy/python-gate/Dockerfile (the SDK package + the canonical proto)
python -m meshweaver.worker --url http://127.0.0.1:8082 --address py/python-kernel

There is no --token: the endpoint is bound to 127.0.0.1, reachable only from containers in the same pod, so reachability is the authentication (see GrpcOptions.TrustedPort and the trusted-gate note in A standalone hub in Python). This is the exact parity with the in-process Roslyn kernel: the C# kernel runs in the portal process; the python gate runs in the portal pod, and a run executes under the requesting user's identity (the gate echoes the delivery's AccessContext), not a standing service credential — nothing to rotate.

Gates are feature-flagged per language under grpc.gates — every language is included by default; a gate runs once its image is supplied (empty image ⇒ no sidecar). Set enabled: false to opt a language out:

grpc:
  gates:
    python:
      image: <registry>/meshweaver/python-gate:<tag>   # deploy/python-gate/Dockerfile
    node:
      image: <registry>/meshweaver/node-gate:<tag>     # deploy/node-gate/Dockerfile — runs js/ts

Each language is its own gate (py/python-kernel, node/node-kernel); the same shape adds the next (bun, a language pool that leases a worker per run/partition). The routing branch (ResolveKernelAddress) and the grpc.gates map are the two places that grow.

Reconnecting…
The server was updated. Reloading the page to pick up the latest version.