description: "fd-3 wire protocol between a Node host and a CPython subprocess for users and maintainers building or debugging the Python code-execution backend."
English | 中文
dsh-code-runtime-python owns the versionless wire protocol between a Node host and a CPython subprocess for the dsh-code-runtime seam: one JSON object per line on the child's fd 3, leaving stdout/stderr free for the program's own output. The package ships the host-side frame codec and hostile-frame validators (src/protocol.ts) plus the Python-side mirror of the same message vocabulary (py/protocol.py), so every consumer of the wire shares one vocabulary. It is the protocol layer for the Python backend — the package carries no subprocess execution path, so nothing here spawns python3 outside the cross-language mirror test. The host treats every inbound frame as hostile, because model code has full access to fd 3 and can post anything through it.
Choose this package when you build or consume the CPython code-runtime wire: implement the Python backend or the host that drives it, or debug a Python code run's framing. The package is the wire protocol intended for a CPython code-runtime provider — such a provider runs each model program in a fresh python3 -I subprocess — and this package supplies the protocol both sides speak, so its exports are the single TS-side source of truth for the wire.
The package re-exports the host-side protocol vocabulary from src/index.ts: validateChildFrame (rebuilds every inbound frame before the host reads it), the lossless-JSON codec and meters (encodeJsonPlain, checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber), and logTruncationMarker (the shared truncation-marker text). The Python side mirrors the message shapes as TypedDicts in py/protocol.py and re-declares the two surfaces both sides execute against — PROTOCOL_FD = 3 and the marker text.
Frames travel on the child's fd 3 as JSON-lines — one object per line — so stdout/stderr stay clear for the program's own output. Child → host: boot-ack, call, log, done. Host → child: boot (first frame, carrying every cap and the namespace declarations), run (after boot-ack, carrying only the program body), and one reply per call. A forged frame can carry both value and error on done, so a consumer must check error first and ignore value when it is set.
Host-side validation drops junk without throwing, so a malformed or forged frame never crashes the host process: validateChildFrame returns undefined for anything that does not rebuild cleanly, a non-number call id can never be echoed into a reply, and forged extra fields never ride along. A completion value that is not lossless JSON, or that exceeds the configured byte budget, is rejected explicitly (non-lossless / over-budget) rather than silently rounded or truncated.
Read these when the protocol contract is not enough. They move from the seam definition to the protocol's design record and the companion backend.
Indirectly, through PTC mode in dsh-tools, which renders the program's completion value or failure into a retained run_code result.
No direct invalidation; the named consumer owns any request-prefix changes.
These limits define what the package does and does not cover; they are current package constraints, not a task backlog.
cpuSeconds is an int on both sides; comparing type declarations across TypeScript and Python has no mechanical equivalent here, so a type-level drift is caught by review plus the backend's real-subprocess suite.src/index.ts exports the protocol vocabulary only — the package carries no subprocess execution path and no Python-side JSON codec, so nothing here spawns python3 outside the mirror test.