完整源码
---
markup: occlusion
title: lib/foreign — foreign kernels v2
description: Structured execution, JSON calls, parallel fan-out, persistent kernels and an explicit state bridge
import:
foreign: lib/foreign.mq.md
stdin: 21
---
# main
`lib/foreign` runs code fences and inline sources with local interpreters. v2 keeps the Markdown surface unchanged while adding structured records, JSON in/out, parallel fan-out, persistent Python/Node kernels and an explicit state bridge.
The same file is still a document: a bound fence is readable Markdown, and `foreign.*` turns it into an executable unit.
---
Probe before you run.
**node = > foreign.probe lang="node"**
> print text=[ok](access(`node`, "ok"))
> print text=[version](access(`node`, "version"))
`probe` returns `{lang, cmd, path, ok, version, error}`. Omit `lang` to inspect every known language.
---
A structured record, not just stdout.
`marker` =
```node
console.log("hello from a foreign kernel");
```
**record = > foreign.invoke code=`marker`**
> print text=[ok](access(`record`, "ok"))
> print text=[stdout](access(`record`, "stdout"))
> print text=[code](access(`record`, "code"))
`invoke` never throws on a process failure. Read `ok`, `code`, `stdout`, `stderr`, `ms`, `timed_out`, `truncated`, `result` and `error` from one record.
---
JSON in, JSON out.
`double` =
```node
let input = "";
process.stdin.on("data", chunk => { input += chunk; });
process.stdin.on("end", () => {
console.log(JSON.stringify(JSON.parse(input) * 2));
});
```
**single = > foreign.call code=`double` input=21**
> print text=`single`
The input is encoded as JSON on stdin; the last stdout value is parsed as JSON. Use `output="json"` with `invoke` when you also want the raw record.
---
Parallel fan-out.
`numbers` =
| value |
|-------|
| 1 |
| 2 |
| 3 |
| 4 |
**doubled = > foreign.call_many code=`double` inputs=`numbers` concurrency=4**
> print text=`doubled`
`call_many` applies one program to every input, runs independently, preserves input order, and returns parsed JSON results. `run_many` does the same for full invoke-option maps.
---
A persistent kernel.
**session = > foreign.session_open lang="node"**
**first = > foreign.session_eval id=`session` source="let total = 0; for (let i = 1; i <= 5; i += 1) total += i;"**
**second = > foreign.session_eval id=`session` source="total * 2"**
> print text=[result](access(`second`, "result"))
Variables created in the first evaluation survive into the second. The kernel is not a shell: use `session_eval`, `session_get`, `session_names`, then `session_close`.
---
The explicit state bridge.
**> foreign.session_set id=`session` name="rate" value=0.08**
**rate = > foreign.session_get id=`session` name="rate"**
> print text=`rate`
**> foreign.session_close id=`session`**
This is a JSON copy, not shared memory. The kernel receives a value; Marqdo receives a value. There is no implicit mirroring and no hidden global namespace.
---
Cells in view.
`foreign.session` owns the document's kernel state. The kernel and cell order are ordinary tables passed as arguments; the names are free:
```text
`分析内核` =
| 名称 | 语言 | 命令 | 说明 |
|------|------|------|------|
| 分析 | python | | shared analysis |
| 复核 | python | | isolated review |
`分析单元` =
| 单元 | 内核 | 说明 |
|------|------|------|
| 准备数据 | 分析 | write state |
| 计算指标 | 分析 | read state |
| 独立复核 | 复核 | isolated kernel |
`会话` = > foreign.session kernels=`分析内核` cells=`分析单元`
```
`view` consumes the `会话` handle and adds Run All, Step, kernel switching, a journal and per-cell state. Without `会话`, view cells are stateless one-shot runs: same shell, no persistent kernel. There is no second CLI mode. See the complete Python walkthrough in [`features/19-foreign-view-cells.mq.md`](../features/19-foreign-view-cells.mq.md).
---
Safety defaults.
| Boundary | Default |
|---|---|
| Execution | requires the host execution capability |
| Shell | no shell; arguments are split explicitly |
| Output | bounded, with truncated |
| Timeout | process group killed on Unix / taskkill /T on Windows |
| CWD | file sandbox root; no implicit escape |
| Parallelism | capped fan-out; each item isolated |
Read the full API in [../../lib/foreign.mq.md](../../lib/foreign.mq.md) and the design in [../../doc/design/foreign-kernel.md](../../doc/design/foreign-kernel.md).