totalfusion 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/AGENTS.md +89 -0
  2. package/CHANGELOG.md +29 -0
  3. package/LICENSE +21 -0
  4. package/README.md +134 -2
  5. package/bin/totalfusion.js +81 -0
  6. package/docs/README.md +40 -0
  7. package/docs/ai.md +82 -0
  8. package/docs/assets/go.svg +1 -0
  9. package/docs/assets/python.svg +1 -0
  10. package/docs/assets/rust.svg +1 -0
  11. package/docs/assets/webassembly.svg +1 -0
  12. package/docs/binary-data.md +60 -0
  13. package/docs/development.md +53 -0
  14. package/docs/errors.md +27 -0
  15. package/docs/flow.md +83 -0
  16. package/docs/getting-started.md +99 -0
  17. package/docs/go.md +99 -0
  18. package/docs/how-it-works.md +53 -0
  19. package/docs/python.md +130 -0
  20. package/docs/reference.md +78 -0
  21. package/docs/rust.md +80 -0
  22. package/docs/security.md +20 -0
  23. package/docs/streaming.md +82 -0
  24. package/docs/total5.md +44 -0
  25. package/docs/tutorials/01-python-action-and-mcp.md +185 -0
  26. package/docs/tutorials/02-wasm-sandbox.md +185 -0
  27. package/docs/tutorials/README.md +12 -0
  28. package/docs/use-cases.md +92 -0
  29. package/docs/webassembly.md +134 -0
  30. package/docs/workers.md +87 -0
  31. package/go/AGENTS.md +25 -0
  32. package/go/README.md +137 -0
  33. package/go/app.go +470 -0
  34. package/go/call.go +88 -0
  35. package/go/duplicate_bsd.go +9 -0
  36. package/go/duplicate_linux.go +10 -0
  37. package/go/errors.go +81 -0
  38. package/go/go.mod +3 -0
  39. package/go/index.js +218 -0
  40. package/go/memory_linux.go +32 -0
  41. package/go/memory_other.go +25 -0
  42. package/go/memory_windows.go +48 -0
  43. package/go/stdout_other.go +13 -0
  44. package/go/stdout_unix.go +28 -0
  45. package/go/stdout_windows.go +43 -0
  46. package/go/value.go +387 -0
  47. package/go/wasm.go +110 -0
  48. package/go/wasm_wasip1.go +70 -0
  49. package/go/wire.go +255 -0
  50. package/index.js +249 -0
  51. package/lib/doctor.js +141 -0
  52. package/lib/errors.js +19 -0
  53. package/lib/options.js +16 -0
  54. package/lib/pool.js +740 -0
  55. package/lib/protocol.js +264 -0
  56. package/lib/stream.js +105 -0
  57. package/lib/watch.js +108 -0
  58. package/llms.txt +50 -0
  59. package/package.json +76 -5
  60. package/python/AGENTS.md +21 -0
  61. package/python/CLAUDE.md +1 -0
  62. package/python/index.js +235 -0
  63. package/python/pip-names.json +16 -0
  64. package/python/sdk/totalfusion.py +42 -0
  65. package/python/worker.py +820 -0
  66. package/rust/AGENTS.md +26 -0
  67. package/rust/Cargo.toml +13 -0
  68. package/rust/README.md +64 -0
  69. package/rust/index.js +219 -0
  70. package/rust/src/app.rs +526 -0
  71. package/rust/src/error.rs +90 -0
  72. package/rust/src/lib.rs +38 -0
  73. package/rust/src/memory.rs +88 -0
  74. package/rust/src/value.rs +393 -0
  75. package/rust/src/wire.rs +176 -0
  76. package/schemas/configure.schema.json +219 -0
  77. package/schemas/contract.schema.json +172 -0
  78. package/scripts/flow-db.js +65 -0
  79. package/total5/AGENTS.md +26 -0
  80. package/total5/CLAUDE.md +1 -0
  81. package/total5/flow/db.json +86 -0
  82. package/total5/flow/events.html +42 -0
  83. package/total5/flow/go.html +43 -0
  84. package/total5/flow/python.html +43 -0
  85. package/total5/flow/rust.html +43 -0
  86. package/total5/flow/stats.html +41 -0
  87. package/total5/flow/stream.html +43 -0
  88. package/total5/flow/wasm.html +43 -0
  89. package/total5/flow.js +249 -0
  90. package/total5/index.js +207 -0
  91. package/wasm/AGENTS.md +27 -0
  92. package/wasm/host.js +226 -0
  93. package/wasm/index.js +169 -0
package/AGENTS.md ADDED
@@ -0,0 +1,89 @@
1
+ # AGENTS.md
2
+
3
+ Guidance for AI coding agents. The first part is for an agent that **uses** TotalFusion in an application; the second is for one that **works on** this repository.
4
+
5
+ ## Project
6
+
7
+ TotalFusion extends Total.js 5 with other runtimes: functions written in **Python, Rust, Go and WebAssembly** are called from Node.js as `async` functions, and become Total.js actions, API routes, MCP tools, Server-Sent Events and nodes of Flow. Each runtime is a pool of worker processes that Node.js supervises; a crash in a worker never takes the application down. The engine (`require('totalfusion')`) does not depend on Total.js; `fusion.register()`, `fusion.sse()` and `fusion.flow()` do.
8
+
9
+ Package name: `totalfusion` (version 0.1.0)
10
+ Node.js: 20 or newer. No dependencies. Plain JavaScript, no TypeScript (Total.js does not support it: never add types or `.d.ts`).
11
+ License: MIT
12
+
13
+ ## Using it
14
+
15
+ Install it with `npm install totalfusion`. The documentation is in `docs/` (start with `docs/getting-started.md`, the tutorials in `docs/tutorials/`, the options in `docs/reference.md`).
16
+
17
+ ```js
18
+ const fusion = require('totalfusion'); // in a Total.js definition: REQUIRE('totalfusion')
19
+
20
+ fusion.configure({
21
+ python: { path: './python', workers: 2 }, // a folder of .py files
22
+ rust: { binary: './worker/target/release/worker' },
23
+ go: { binary: './worker/worker' },
24
+ wasm: { module: './module.wasm' } // one module for each Fusion
25
+ });
26
+
27
+ await fusion.python('module.function', args); // also fusion.rust(), fusion.go(), fusion.wasm()
28
+ for await (const chunk of fusion.python.stream('module.generator', args)) { }
29
+ ```
30
+
31
+ - **Total.js:** `await fusion.register({ python: { path: PATH.root('python') }, watch: DEBUG })` turns every function that declares a contract into an action (`module/function`). Then `ROUTE('API /api/ +module_function --> module/function')`. Do not `require('totalfusion/total5')`: Total.js does not accept that form; everything is on the main package.
32
+ - **Contracts** are the schema syntax of Total.js: Python `@action(summary=..., input='*text:String', output=..., mcp=True)`; Rust `.summary().input().mcp(true)`; Go `.Summary().Input().MCP(true)`. A function without a contract is callable from JavaScript but is **not** an action. `*` means required.
33
+ - **Errors:** `ValueError` (Python), `Error::invalid` (Rust) and `Invalid` (Go) are mistakes of the caller: Total.js sends their message to the client. Every other failure answers "The action failed" and the detail goes to the log.
34
+ - **MCP:** only functions that say `mcp` become tools, and the endpoint (`$mcp : true` in `config`) has **no authentication** unless you add one. Never turn it on in an application that listens on a public address without authentication.
35
+ - **A worker's standard output carries the protocol.** In Python, Rust and Go the SDK redirects `print` and `fmt.Println` to the error output, but write to the error output on purpose.
36
+ - **WebAssembly** modules run in a sandbox (no files, no network, no environment) and are WASI reactors with a small ABI (`docs/webassembly.md`). A runtime has one module: use one `new Fusion({ wasm: ... })` for each module. The SDK is in Go (`app.Wasm()` in `init`, Go 1.24 or newer).
37
+ - **A route with a dot in a segment** (`/x/discount.apply/`) looks like a file to Total.js and gets an empty reply: split the function name across segments.
38
+ - **Nothing is downloaded, compiled or installed for you.** Workers are built by the user (`cargo build --release`, `go build`).
39
+ - **Check the setup first:** `npx totalfusion doctor --path ./python` (also `--runtime rust|go|wasm` with `--binary` or `--module`). For Python it reads the components without importing them; for Rust and Go it executes the worker with `--describe`, and for WebAssembly it runs the host to read the module contract. Use trusted native workers. It says what to fix; with `--json` it prints `{ ok, checks: [{ status, name, message, fix }] }` and the exit code is `0`, `1` (something to fix) or `2` (wrong usage). Run the command of `fix` instead of guessing.
40
+ - **Flow:** seven components (Python, Rust, Go, WebAssembly, Stream, Events, Stats) in `total5/flow/`, listed in `total5/flow/db.json`; see `docs/flow.md`.
41
+ - **More for models:** `llms.txt` (an index of the documentation), `llms-full.txt` (all of it in one file), `schemas/configure.schema.json` (the options of `fusion.configure()` and of a call) and `schemas/contract.schema.json` (a contract and what `--describe` prints). `docs/ai.md` explains them.
42
+
43
+ ## Repository layout
44
+
45
+ Each area (`go/`, `rust/`, `python/`, `wasm/`, `total5/`, `tests/`) has its own `AGENTS.md` with the rules of that area: read it before you change files there.
46
+
47
+ - `index.js` is the `Fusion` class and the entry point. `lib/` is the engine: `pool.js` (workers, queue, timeouts, recycling, health check, retries), `protocol.js` (frames), `stream.js`, `watch.js`, `doctor.js`, `options.js`, `errors.js`.
48
+ - `python/`, `rust/`, `go/`, `wasm/` are the runtimes: each has an adapter (`index.js`) and its worker or SDK (`worker.py` and `sdk/`; the `totalfusion` crate in `rust/src`; the Go module in `go/*.go`; `wasm/host.js`).
49
+ - `total5/` is the Total.js integration: `index.js` (`register`, `sse`), `flow.js` and `flow/*.html` (the components of Flow).
50
+ - `bin/totalfusion.js` is the `doctor` command. `scripts/flow-db.js` builds `total5/flow/db.json`; `scripts/llms.js` builds `llms.txt` and `llms-full.txt`.
51
+ - For Codex: this file is the native entry point; no separate Codex instructions file is needed. Start the chat in the TotalFusion repository so instructions and repo-local skills are discovered. The four entries in `.agents/skills/` reuse the shared checklists in `.claude/skills/`; read their linked checklist when a workflow applies. See `docs/ai.md`.
52
+ - For agents: this file, `CLAUDE.md` and `GEMINI.md` (they import it), `.github/copilot-instructions.md`, `.claude/skills/` (four checklists: add a function, diagnose a worker, add a tutorial, verify a change) and `.claude/settings.json` (the commands that are safe to run without asking), `schemas/` and `llms.txt`.
53
+ - `tests/` has the tests and the workers they run (`tests/go`, `tests/rust`, `tests/wasm`, `tests/components`). `examples/` has the examples (`examples/README.md` lists them, and `tests/examples.test.js` runs them) and the applications of the tutorials (`examples/tutorials`). `docs/` is the documentation, and it is tested.
54
+ - `.github/workflows/test.yml` runs the suite on Linux (Node.js 20, 22, 24), macOS and Windows.
55
+
56
+ ## Commands
57
+
58
+ ```bash
59
+ npm test # the whole suite (node --test)
60
+ npm run check # the fast checks: documentation, files for agents, package
61
+ npm run generate # llms.txt, llms-full.txt and total5/flow/db.json
62
+ node --test tests/go.test.js # one file
63
+ npm run test:rust # cargo test of the crate
64
+ npm run test:go # go test of the module
65
+ node scripts/flow-db.js --write # only the list of components of Flow
66
+ node scripts/llms.js --write # only llms.txt and llms-full.txt
67
+ npx totalfusion doctor --path tests/components
68
+ npm pack --dry-run # what goes into the package
69
+ ```
70
+
71
+ `npm test` needs Python 3.9 or newer. The tests of Rust run if `cargo` is found, the ones of Go if `go` is found (`GO=/path/to/go`), the ones of WebAssembly and the tutorial 2 if that Go is 1.24 or newer, and the ones of Total.js and Flow if Total.js 5 is found (`TOTAL5_PATH`, the `total5` package or a sibling `../framework5`). Without them those tests are skipped, not failed. See `CONTRIBUTING.md`.
72
+
73
+ ## Conventions
74
+
75
+ - Plain JavaScript in the style of Total.js: tabs, `'use strict'`, no dependencies. Rust follows `rustfmt`, Go follows `gofmt`.
76
+ - The protocol is version 2 (`lib/protocol.js`): the Python worker, the Rust crate, the Go module and the host of WebAssembly all speak it. A change in one is a change in all.
77
+ - A change comes with tests, and a test must be able to fail: **break the code on purpose and see the test fail** before you trust it.
78
+ - The documentation is part of the product and is tested (`tests/docs.test.js`: links, anchors, titles, reachability). A new page goes in `docs/README.md` and in `PAGES` of `scripts/llms.js`; `tests/agents.test.js` fails if it is missing. Say what was measured and where, what was verified and what was not. Do not write numbers from memory: run it.
79
+ - A tutorial is a page in `docs/tutorials` and an application in `examples/tutorials` with the same name and a `verify.js`; `tests/tutorials.test.js` runs it. Write the outputs of the page from what the application printed.
80
+ - Every replacement that a script does must assert that its pattern matched: a silent no-op looks like success.
81
+
82
+ ## Pitfalls
83
+
84
+ - **Windows:** an executable that is running cannot be replaced (the Rust and Go workers run from a copy: `shadowCopy`). In Go, never make a second `os.File` for a handle that another `os.File` owns: the finalizer of the first closes it at the first garbage collection (`go/stdout_windows.go`). Checkouts have CRLF line endings: split text with `/\r?\n/`.
85
+ - **Python:** run the tests with `PYTHONDONTWRITEBYTECODE` unset (`env -u PYTHONDONTWRITEBYTECODE npm test`); the components are loaded from source, never from bytecode (`stale.test.js`).
86
+ - **Make failures loud.** A worker that exits silently hides its cause: print the reason to the error output and exit non-zero.
87
+ - **Processes:** a script that waits for workers or watchers needs its own keep-alive timer, because idle workers are `unref`'d. Tests that start an application must spawn it with an IPC channel (`stdio: [..., 'ipc']`), or Total.js starts its debug watcher and the process cannot be stopped cleanly.
88
+ - **Flow:** the icon font of Flow is not Tabler: use names from the icon list of Flow (public/icons-db.html in its repository) or nothing shows.
89
+ - **Do not commit** built workers or modules (`target/`, `plugins/*.wasm`, `__pycache__`, `*.js.map`), and leave no files in the temporary directory after the tests.
package/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ The first version.
6
+
7
+ - **Documentation:** a short README and a `docs/` folder with a guide, one page per runtime (Python, Rust and Go), use cases with their measured numbers, a reference and the security notes.
8
+ - **Runtimes:** Python (3.9 or newer), Rust and Go (1.21 or newer), as pools of worker processes that Node.js supervises. They speak the same protocol (version 2), so every feature below works with all of them. The Go module is pure Go (no `cgo`), so a worker builds for any system from any system.
9
+ - **Calls:** correlated by id, with timeouts, `AbortSignal` cancellation, a bounded queue, and real tracebacks (Python) or errors with a name and a code (Rust and Go) in the JavaScript error. A call is never retried by itself: it may have had side effects.
10
+ - **Contracts:** `@action(...)` in Python, `.summary().input().output()...` in Rust and `.Summary().Input().Output()...` in Go declare what a function takes and returns, in the schema syntax of Total.js. They are read without running any code.
11
+ - **WebAssembly:** a module (`.wasm`, a WASI reactor that exports a small ABI) runs in a sandbox in a process of its own: no files, no network, no environment, only WASI as imports, a trap or an exit fails the call and starts a new instance. The Go SDK (`app.Wasm()`, Go 1.24 or newer) builds one; the ABI is documented for other languages. Streams and concurrency inside a worker are not supported.
12
+ - **Total.js 5:** `fusion.register()` turns the functions that declare a contract into `NEWACTION()`s, with `input`, `query`, `params` and access options (`permissions`, `user`, `sa`, `su`) validated by the framework, and into MCP tools when the function says `mcp`. Server-Sent Events (`fusion.sse`) are included.
13
+ - **Flow:** seven components for Total.js Flow (group *TotalFusion*): one for each runtime that calls a function with the data of each message, **Stream** (every chunk is a message, with `Stop` and cancellation when the flow stops), **Events** (the events of the workers as messages) and **Stats**. A list for the catalog of the designer (`total5/flow/db.json`) and `fusion.flow()` for the logic. They were run in the designer of Flow 11.1.
14
+ - **Tutorials:** step by step pages (`docs/tutorials`), each with an application in `examples/tutorials` that a test of the project starts and checks on every change. The first one: a Python function as an API and as a tool for an AI agent, with live reload. The second: the code of third parties in the sandbox of WebAssembly, with a module that tries to get out and one that never returns.
15
+ - **For agents and models:** `AGENTS.md` (also in the package) says how to use TotalFusion in an application and how to work on the repository; `CLAUDE.md`, `GEMINI.md` and the instructions of Copilot lead to it; four skills for Claude Code (`.claude/skills`) and its shared settings; `llms.txt` and `llms-full.txt` built from the documentation; JSON Schemas of the configuration and of the contracts (`schemas/`); and `docs/ai.md`. A test keeps them true.
16
+ - **For a public repository:** `SECURITY.md` (private reporting), templates for issues (the bug report asks for the output of `doctor --json`) and for pull requests, an index of the examples that a test runs (`tests/examples.test.js`), the badge of the tests, and an `AGENTS.md` in each area (`go`, `rust`, `python`, `wasm`, `total5`, `tests`).
17
+ - **Publishing:** a workflow publishes the package to npm when a release is created on GitHub (after the tests and `scripts/release-check.js`), with a token or with trusted publishing; `CONTRIBUTING.md` says how to set it up.
18
+ - **Binary data** without base64: `Buffer` and typed arrays travel as raw bytes in both directions (NumPy arrays included). A 100 MB buffer makes the round trip in 43 ms.
19
+ - **Streaming:** generators in Python and stream functions in Rust and Go become async iterables, with backpressure and cancellation.
20
+ - **Several calls at the same time** in a worker (`concurrency`), for async functions in Python for the threads of a Rust worker and for the goroutines of a Go one.
21
+ - **Keeping workers healthy:** recycling by number of calls and by memory with no call lost (the replacement starts first), a health check of the idle workers, `warmup`, `preload` and `@startup`/`@shutdown` hooks.
22
+ - **Events:** `fusion` is an `EventEmitter` that reports when workers are ready, end, are replaced or stop answering, when a call is repeated and when the code is reloaded.
23
+ - **Retrying:** a call that is declared idempotent (`{ idempotent: true }`, `@action(idempotent=True)` or `.idempotent(true)` in Rust, `.Idempotent(true)` in Go) is repeated on another worker if its worker dies. Nothing is repeated otherwise.
24
+ - **Rust and Go on Windows:** the worker runs from a copy, so `cargo build` or `go build` can replace the binary while it is in use and the reload picks the new build up (`shadowCopy`).
25
+ - **Fresh code:** the components of a Python worker are loaded from their source every time, never from bytecode (a file saved twice within a second with the same size is never missed), and no `__pycache__` is left next to them.
26
+ - **Development:** `fusion.watch()` replaces the workers when the code changes, and with Total.js the contracts are read again.
27
+ - **Diagnosis:** `fusion.doctor()` and `npx totalfusion doctor` check the interpreter (or the Rust or Go binary), the components, the libraries and `requirements.txt` without importing or installing anything, and the errors at run time say how to install a missing library.
28
+
29
+ Verified in GitHub Actions on Linux (Ubuntu with Node.js 20, 22 and 24 and Python 3.9 to 3.14), macOS and Windows: the whole suite, with the Python, Rust, Go and WebAssembly workers and the components for Flow. Also locally on macOS (Apple silicon) with Node.js 20, 22, 24 and 26, Python 3.9 to 3.15, Rust 1.99 and Go 1.21 and 1.27, and by hand in the designer of Flow 11.1. The MCP endpoint is not in the release 0.0.19 of `total5` in npm, so it was verified against the development version (0.0.20-1) on macOS, not in GitHub Actions. Not verified: a specific AI client against the MCP endpoint, and Flow in the cloud service of Total.js.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Spanish Total.js Platform
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,135 @@
1
- # Temporary Holding Version
1
+ # TotalFusion
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ <p align="center">
4
+ <a href="docs/python.md"><img src="docs/assets/python.svg" alt="Python" height="56"></a>&nbsp;&nbsp;&nbsp;&nbsp;
5
+ <a href="docs/rust.md"><img src="docs/assets/rust.svg" alt="Rust" height="56"></a>&nbsp;&nbsp;&nbsp;&nbsp;
6
+ <a href="docs/go.md"><img src="docs/assets/go.svg" alt="Go" height="56"></a>&nbsp;&nbsp;&nbsp;&nbsp;
7
+ <a href="docs/webassembly.md"><img src="docs/assets/webassembly.svg" alt="WebAssembly" height="56"></a>
8
+ </p>
9
+
10
+ <p align="center"><sub>Python, Rust, Go and WebAssembly &middot; for Total.js and Node.js</sub></p>
11
+
12
+ <p align="center"><a href="https://github.com/totaljs-es/totalfusion/actions/workflows/test.yml"><img src="https://github.com/totaljs-es/totalfusion/actions/workflows/test.yml/badge.svg" alt="Tests on Linux, macOS and Windows"></a></p>
13
+
14
+ **Extends Total.js with other runtimes.** Call functions written in Python, Rust and Go from Total.js and Node.js as plain `async` functions, and use them as Actions, API endpoints and MCP tools for AI agents, without leaving JavaScript. WebAssembly modules run in a sandbox.
15
+
16
+ ```python
17
+ # python/sentiment.py
18
+ from totalfusion import action
19
+
20
+ @action(summary='Detects the sentiment of a text', input='*text:String', output='label:String', mcp=True)
21
+ def analyze(data):
22
+ return { 'label': 'POSITIVE' if 'love' in data['text'] else 'NEGATIVE' }
23
+ ```
24
+
25
+ ```js
26
+ // Total.js application
27
+ const fusion = REQUIRE('totalfusion');
28
+
29
+ fusion.register({ python: { path: PATH.root('python') } });
30
+
31
+ // 'sentiment/analyze' is now a Total.js action: ACTION(), API routes and an MCP tool for AI agents
32
+ const result = await ACTION('sentiment/analyze', { text: 'I love it' }).promise();
33
+ ```
34
+
35
+ Total.js validates the input against the contract before Python runs. The engine (`require('totalfusion')`) is plain Node.js and does not depend on Total.js, so `fusion.python('sentiment.analyze', data)` also works in any Node.js program.
36
+
37
+ ## What you get
38
+
39
+ - **Python, Rust and Go workers** that Node.js supervises: a pool of long-lived processes, correlated calls, timeouts, cancellation and real errors (with the traceback in Python). A crash in a worker never takes your application down. → [Python](docs/python.md), [Rust](docs/rust.md), [Go](docs/go.md)
40
+ - **A sandbox**: a WebAssembly module runs without files, network or environment, in one file that works on any system. → [WebAssembly](docs/webassembly.md)
41
+ - **Total.js integration**: the functions that declare a contract become actions with validated `input`, `query` and `params`, permissions, API routes, MCP tools, and Server-Sent Events. → [Total.js 5](docs/total5.md)
42
+ - **Seven components for Flow**: call a function of any runtime from a node, stream chunks as messages, send the events of the workers to an alert and read the stats. They were run in the designer of Flow. → [Flow](docs/flow.md)
43
+ - **Binary data without base64**: `Buffer` and typed arrays travel as raw bytes in both directions, NumPy arrays included. A 100 MB buffer makes the round trip in 43 ms. → [Binary data](docs/binary-data.md)
44
+ - **Streaming** with backpressure and cancellation: a generator in Python or a stream function in Rust or Go is an async iterable. → [Streaming](docs/streaming.md)
45
+ - **Several calls at once** in one worker, for calls that wait, and for the threads of a Rust worker or the goroutines of a Go one. → [Working with the workers](docs/workers.md)
46
+ - **Workers that stay healthy**: replaced after a number of calls or when they use too much memory, with no call lost, and checked while idle. Events for your logs. Optional retry of calls that you declare idempotent. → [Working with the workers](docs/workers.md)
47
+ - **Development reload**: save a file and the next call runs the new code. → [Development](docs/development.md)
48
+ - **A `doctor`** that tells you what is missing, and the exact command to fix it, before anything runs. → [Development](docs/development.md#checking-your-setup)
49
+
50
+ ## Runtimes
51
+
52
+ | | | |
53
+ |---|---|---|
54
+ | [Python](docs/python.md) | Available | Machine learning, scientific computing, any Python library. Python 3.9 or newer. |
55
+ | [Rust](docs/rust.md) | Available | Speed, many threads, a small footprint. You build a binary; running it does not need Rust. |
56
+ | [WebAssembly](docs/webassembly.md) | Available | Code in a sandbox, in one `.wasm` file for every system. Go is the language with an SDK today. |
57
+ | [Go](docs/go.md) | Available | Network and infrastructure code, many calls at once, one binary that you can build for any system. You build a binary; running it does not need Go. |
58
+
59
+ ## Why not just `child_process`?
60
+
61
+ A process per call costs about 17.6 ms to start. A worker that is already running answers a small call in 0.07 ms (Python) or 0.03 ms (Rust and Go), and keeps your model in memory. Beyond speed you get what you would otherwise write yourself: a pool, a bounded queue, timeouts, cancellation, restart of workers that die, memory limits, streaming, binary transfer and the contracts that make a function an action. [Use cases](docs/use-cases.md) has the cases with their numbers, and [Where it does not fit](docs/use-cases.md#where-it-does-not-fit) says when not to use it.
62
+
63
+ ## Install
64
+
65
+ ```bash
66
+ npm install totalfusion
67
+ ```
68
+
69
+ It needs Node.js 20 or newer, and Python 3.9 or newer for the Python runtime. Rust and Go are needed only to build a worker in that language. **TotalFusion never installs, downloads or compiles anything for you.** → [Getting started](docs/getting-started.md)
70
+
71
+ ## Documentation
72
+
73
+ | | |
74
+ |---|---|
75
+ | [Getting started](docs/getting-started.md) | Install it, call your first function, make it an action. |
76
+ | [Tutorials](docs/tutorials/README.md) | Step by step, each with an application that is tested on every change. |
77
+ | [Use cases](docs/use-cases.md) | What it is good for, with the numbers that were measured. |
78
+ | [Python](docs/python.md) · [Rust](docs/rust.md) · [Go](docs/go.md) | One page per runtime. |
79
+ | [Total.js 5](docs/total5.md) · [Flow](docs/flow.md) | Actions, validation, permissions, MCP, SSE. The components for Flow. |
80
+ | [Binary data](docs/binary-data.md) · [Streaming](docs/streaming.md) | The two big features of the transfer. |
81
+ | [Working with the workers](docs/workers.md) | Concurrency, recycling, health check, events, retrying. |
82
+ | [Errors and cancellation](docs/errors.md) | The error codes. |
83
+ | [Development and diagnosis](docs/development.md) | Reload on change and the `doctor`. |
84
+ | [AI assistants](docs/ai.md) | `AGENTS.md`, `llms.txt`, the schemas and your functions as tools for agents. |
85
+ | [How it works](docs/how-it-works.md) | The pool, the workers and the protocol. |
86
+ | [Security](docs/security.md) | What it protects and what it does not. |
87
+ | [Reference](docs/reference.md) | Every option, method and command. |
88
+
89
+ The index of the documentation is [docs/README.md](docs/README.md).
90
+
91
+ ## Examples
92
+
93
+ All of them run from a clone of the repository:
94
+
95
+ | | |
96
+ |---|---|
97
+ | [examples/totaljs-app](examples/totaljs-app) | A Total.js 5 application with Python: actions, an API route, Server-Sent Events and reload on edit. `npm install && npm start`. |
98
+ | [examples/totaljs-numerics](examples/totaljs-numerics) | Total.js 5 with NumPy statistics, a Rust Action and binary typed arrays. |
99
+ | [examples/basic.js](examples/basic.js) | `fusion.python()` in any Node.js program. |
100
+ | [examples/streaming.js](examples/streaming.js) | A Python generator as an async iterable, and cancelling it. |
101
+ | [examples/rust.js](examples/rust.js) | The Rust worker of [examples/rust](examples/rust) (build it first with `cargo build --release`). |
102
+ | [examples/go.js](examples/go.js) | The Go worker of [examples/go](examples/go) (build it first with `go build -o worker`). |
103
+ | [examples/wasm.js](examples/wasm.js) | The WebAssembly module of [examples/wasm](examples/wasm) (build it first, see the file). |
104
+ | [examples/components](examples/components) | Components that use scikit-learn, NumPy and PyTorch (they need those libraries in your Python). |
105
+
106
+ ## Status
107
+
108
+ Version 0.1.0. The whole test suite (more than 410 tests: Python, Rust, Go, WebAssembly and the components for Flow) **passes in GitHub Actions on Linux, macOS and Windows**, and it was run locally on macOS as well:
109
+
110
+ | | Where it has run |
111
+ |---|---|
112
+ | Linux | GitHub Actions on Ubuntu: Node.js 20, 22 and 24 with Python 3.9 to 3.14 |
113
+ | macOS | GitHub Actions (Node.js 24, Python 3.12) and locally on Apple silicon (Node.js 20, 22 and 24, Python 3.9 to 3.15) |
114
+ | Windows | GitHub Actions (Node.js 24, Python 3.12): the whole suite, including the binary pipes, the memory of a worker and the Rust, Go and WebAssembly workers |
115
+ | Rust | The stable toolchain of the runners, and 1.99 locally (the `totalfusion` crate and its worker) |
116
+ | Go | The stable toolchain of the runners on the three systems, and locally with Go 1.21 and 1.27 (the module with the race detector, and the 62 tests of its worker) |
117
+ | WebAssembly | GitHub Actions on the three systems (Node.js 20, 22 and 24 on Linux), and locally with Node.js 26: the 50 tests of the module, including a module that tries to get out |
118
+ | Flow | The test harness of Total.js on the three systems, and by hand in the designer of Flow 11.1 on macOS |
119
+ | Total.js | `total5` from npm (0.0.19) in GitHub Actions, and the development version 0.0.20-1 locally. **The MCP endpoint is not in 0.0.19**, so it is checked only against the development version, on macOS |
120
+
121
+ Python 3.15 and the combinations that are not in the matrix of [.github/workflows/test.yml](.github/workflows/test.yml) were run only locally.
122
+
123
+ Not verified: connecting a specific AI client to the MCP endpoint, and the components for Flow in the cloud service of Total.js.
124
+
125
+ ## Contributing
126
+
127
+ To report a vulnerability, see [SECURITY.md](SECURITY.md). See [CONTRIBUTING.md](CONTRIBUTING.md) for how to run the tests and how the project is organised, and [CHANGELOG.md](CHANGELOG.md) for what each version contains. **AI coding agents:** [AGENTS.md](AGENTS.md) says how to use TotalFusion in an application and how to work on this repository; it is also in the package.
128
+
129
+ ## Credits
130
+
131
+ The logos of Python, Rust, Go and WebAssembly in the header come from [Simple Icons](https://simpleicons.org) (version 16.35.0, CC0) and only identify the languages and the technology. Python is a trademark of the Python Software Foundation, Rust of the Rust Foundation and Go of Google, and WebAssembly is a standard of the W3C. TotalFusion is not affiliated with or endorsed by any of them. The files are in [docs/assets](docs/assets) and can be replaced by other versions of the logos.
132
+
133
+ ## License
134
+
135
+ MIT
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // totalfusion doctor [--runtime python|rust|go|wasm] [--path DIR] [--venv DIR] [--python COMMAND] [--requirements FILE] [--preload a,b]
5
+ // [--binary FILE] [--module FILE] [--max-memory 2gb] [--json]
6
+ //
7
+ // Checks the interpreter, the components and the libraries they need, without importing or installing anything.
8
+ // Exit code: 0 when everything is in order (warnings are only advice), 1 when something has to be fixed, 2 for a wrong usage.
9
+
10
+ const fusion = require('..');
11
+
12
+ const options = { string: ['runtime', 'path', 'venv', 'python', 'requirements', 'preload', 'binary', 'module', 'max-memory'] };
13
+ const args = process.argv.slice(2);
14
+ const command = args[0] && !args[0].startsWith('-') ? args.shift() : null;
15
+ const values = {};
16
+ let json = false;
17
+
18
+ for (let i = 0; i < args.length; i++) {
19
+
20
+ const flag = args[i].replace(/^--/, '');
21
+
22
+ if (flag === 'json') {
23
+ json = true;
24
+ continue;
25
+ }
26
+
27
+ if (!args[i].startsWith('--') || !options.string.includes(flag) || args[i + 1] == null || args[i + 1].startsWith('--')) {
28
+ console.error('Unknown or incomplete option: ' + args[i]);
29
+ process.exit(2);
30
+ }
31
+
32
+ values[flag] = args[++i];
33
+ }
34
+
35
+ if (command !== 'doctor') {
36
+ console.error('Usage: totalfusion doctor [--runtime python|rust|go|wasm] [--path DIR] [--venv DIR] [--python COMMAND] [--requirements FILE] [--preload a,b] [--binary FILE] [--module FILE] [--max-memory 2gb] [--json]');
37
+ process.exit(2);
38
+ }
39
+
40
+ const config = {};
41
+
42
+ if (values.path)
43
+ config.path = values.path;
44
+
45
+ if (values.venv)
46
+ config.venv = values.venv;
47
+
48
+ if (values.python)
49
+ config.python = values.python;
50
+
51
+ if (values.requirements)
52
+ config.requirements = values.requirements;
53
+
54
+ if (values.preload)
55
+ config.preload = values.preload.split(',');
56
+
57
+ if (values.binary)
58
+ config.binary = values.binary;
59
+
60
+ if (values.module)
61
+ config.module = values.module;
62
+
63
+ if (values['max-memory'])
64
+ config.maxMemory = values['max-memory'];
65
+
66
+ const runtime = values.runtime || (values.binary ? 'rust' : values.module ? 'wasm' : 'python');
67
+
68
+ if (!['python', 'rust', 'go', 'wasm'].includes(runtime)) {
69
+ console.error('Unknown runtime: ' + runtime);
70
+ process.exit(2);
71
+ }
72
+
73
+ fusion.configure({ [runtime]: config });
74
+
75
+ fusion.doctor(runtime).then(function(report) {
76
+ console.log(json ? JSON.stringify(report, null, 2) : report.text);
77
+ process.exit(report.ok ? 0 : 1);
78
+ }, function(err) {
79
+ console.error(err.message);
80
+ process.exit(2);
81
+ });
package/docs/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Documentation
2
+
3
+ TotalFusion extends Total.js with other runtimes. These pages explain how to use it. The [README of the project](../README.md) is the short version.
4
+
5
+ ## Start here
6
+
7
+ | | |
8
+ |---|---|
9
+ | [Getting started](getting-started.md) | Install it, call your first function, and make it an action of Total.js. |
10
+ | [Tutorials](tutorials/README.md) | Step by step, with an application that is tested on every change. |
11
+ | [Use cases](use-cases.md) | What it is good for, with the numbers that were measured. |
12
+ | [How it works](how-it-works.md) | The pool, the workers and the protocol. |
13
+
14
+ ## The runtimes
15
+
16
+ | | |
17
+ |---|---|
18
+ | [Python](python.md) | Machine learning and any Python library. Available. |
19
+ | [Rust](rust.md) | Speed, threads and a small footprint. Available. |
20
+ | [Go](go.md) | Network and infrastructure code, many calls at once, easy to build for any system. Available. |
21
+ | [WebAssembly](webassembly.md) | Functions in a sandbox, in one file that runs on any system. Available. |
22
+
23
+ ## Features that every runtime shares
24
+
25
+ | | |
26
+ |---|---|
27
+ | [Total.js 5](total5.md) | Actions, validation, permissions, API routes, MCP tools and Server-Sent Events. |
28
+ | [Flow](flow.md) | Seven components for Total.js Flow: call a function, stream chunks, watch the workers and read the stats. |
29
+ | [Binary data](binary-data.md) | Buffers and typed arrays without base64. |
30
+ | [Streaming](streaming.md) | Generators as async iterables, with backpressure and cancellation. |
31
+ | [Working with the workers](workers.md) | Concurrency, recycling, the health check, events and retrying. |
32
+ | [Errors and cancellation](errors.md) | The error codes and how a call is cancelled. |
33
+ | [Development and diagnosis](development.md) | Reload when the code changes, and the `doctor`. |
34
+ | [AI assistants](ai.md) | The files for models and agents, the schemas, and your functions as tools. |
35
+ | [Security](security.md) | What it protects and what it does not. |
36
+ | [Reference](reference.md) | Every option, method and command. |
37
+
38
+ ## About the project
39
+
40
+ [Changelog](../CHANGELOG.md) · [Contributing](../CONTRIBUTING.md) · [The Rust crate](../rust/README.md) · [The Go module](../go/README.md)
package/docs/ai.md ADDED
@@ -0,0 +1,82 @@
1
+ # Using TotalFusion with AI assistants
2
+
3
+ Two things are in this page: how to give an assistant (or an agent) what it needs to **write code that uses TotalFusion**, and how your functions become **tools that an agent can call**. Every file mentioned here is kept true by a test of the project (`tests/agents.test.js`).
4
+
5
+ ## What to give your assistant
6
+
7
+ | File | What it is | Give it when |
8
+ |---|---|---|
9
+ | [AGENTS.md](../AGENTS.md) | Instructions: how to use TotalFusion in an application, how the repository is organised, the commands, and the pitfalls to avoid. It is also in the npm package, at `node_modules/totalfusion/AGENTS.md`. | The assistant works in your application or in this repository. |
10
+ | [llms.txt](../llms.txt) | An index of the documentation, in the format of [llmstxt.org](https://llmstxt.org): one line and one link for each page. | The assistant can read links and you want it to choose what to read. |
11
+ | [llms-full.txt](../llms-full.txt) | All the documentation in one file. | The assistant cannot read links, or you want it to have everything at once. |
12
+ | [schemas/configure.schema.json](../schemas/configure.schema.json) | JSON Schema of `fusion.configure()` and of the options of a call. | To validate a configuration, or to let an editor complete it. |
13
+ | [schemas/contract.schema.json](../schemas/contract.schema.json) | JSON Schema of the contract of a function and of what a worker prints with `--describe`. | To write a worker in another language, or to check one. |
14
+
15
+ `llms.txt` and `llms-full.txt` are built from the pages of the repository (`node scripts/llms.js --write`), so they cannot be out of date: a test fails if they are.
16
+
17
+ If your assistant takes a block of instructions of your own, this is enough to start (it is the essence of `AGENTS.md`):
18
+
19
+ ```
20
+ This project uses TotalFusion (https://github.com/totaljs-es/totalfusion) to call functions written in
21
+ Python, Rust, Go and WebAssembly from Total.js 5 and Node.js. Read node_modules/totalfusion/AGENTS.md first.
22
+ - A function that declares a contract (@action in Python, .summary().input() in Rust, .Summary().Input() in Go)
23
+ becomes a Total.js action with fusion.register(); only functions that say mcp become tools for AI agents.
24
+ - The standard output of a worker carries the protocol: write to the error output.
25
+ - Check the setup with: npx totalfusion doctor --json
26
+ - A WebAssembly module runs in a sandbox (no files, no network, no environment); one module for each Fusion.
27
+ - The MCP endpoint has no authentication unless you add one: never expose it without.
28
+ ```
29
+
30
+ ## Your functions as tools for agents
31
+
32
+ A function with a contract and `mcp=True` (Python), `.mcp(true)` (Rust) or `.MCP(true)` (Go) is offered by the MCP endpoint of Total.js as a tool: its name, its description, the schema of its arguments and the schema of its result come **from the contract**, so you write them once. The [first tutorial](tutorials/01-python-action-and-mcp.md) does it from the start and shows the real answers of `tools/list` and `tools/call`.
33
+
34
+ Two things to decide before you do it for real: **which functions** the agent may call (an agent sees only what you say, so leave the rest without `mcp`), and **who may reach the endpoint** (it has no authentication unless you add one with `Total.mcp.auth`). See [Security](security.md).
35
+
36
+ ## Let an agent check the environment
37
+
38
+ ```bash
39
+ npx totalfusion doctor --json
40
+ ```
41
+
42
+ It prints one JSON object, and the exit code says the result: `0` when everything is in order, `1` when something has to be fixed, `2` for a wrong usage.
43
+
44
+ ```json
45
+ {
46
+ "runtime": "python",
47
+ "ok": false,
48
+ "checks": [
49
+ { "status": "error", "name": "Libraries", "message": "numpy used by stats needs to be installed", "fix": "/project/.venv/bin/python -m pip install numpy" }
50
+ ],
51
+ "text": "TotalFusion doctor: python ..."
52
+ }
53
+ ```
54
+
55
+ Each check has a `status` (`ok`, `warn` or `error`), a `name`, a `message` and, when there is something to do, the exact command in `fix`. An agent can run the command of `fix` instead of guessing. For Python, the doctor reads components without importing them. For Rust and Go it executes the worker with `--describe`; for WebAssembly the host reads the module contract inside its sandbox. A native worker still has the permissions of its user during discovery: use a trusted binary. See [Development and diagnosis](development.md).
56
+
57
+ ## For agents that work on the repository
58
+
59
+ The repository has the files that the common agents look for. They all lead to the same instructions, so there is only one text to keep true:
60
+
61
+ - `AGENTS.md`: the instructions. Each area of the repository (`go`, `rust`, `python`, `wasm`, `total5`, `tests`) has its own, with a `CLAUDE.md` that imports it, because Claude Code loads the `CLAUDE.md` of a folder when it works there.
62
+ - Codex reads `AGENTS.md` directly. Its four repo-local skill entry points are in `.agents/skills/`, and each links to the corresponding checklist in `.claude/skills/`. The checklist stays in one place.
63
+ - `CLAUDE.md` and `GEMINI.md`: they import `AGENTS.md`.
64
+ - `.github/copilot-instructions.md`: a short version for GitHub Copilot, with the rules that matter most.
65
+ - `.claude/skills/`: four skills for Claude Code (add a function to an application, diagnose a worker that fails, add a tutorial, verify a change). Each one is a checklist with the real commands.
66
+ - `.claude/settings.json`: the commands that are safe to run without asking (the tests, `npm run check`, read-only git).
67
+
68
+ ## Codex
69
+
70
+ Start a Codex chat with this repository as the workspace. Codex reads the root `AGENTS.md` and instructions along the path to its working directory. When working in another area, read that area's `AGENTS.md` before editing it. If your chat started in another project, explicitly read this repository's instructions; mentioning its path does not change the chat's workspace.
71
+
72
+ The skills in `.agents/skills/` expose the same four workflows as Claude Code: add a function, diagnose a worker, add a tutorial and verify a change. Codex can select one when its description matches the task; you can also ask for it explicitly, for example `$totalfusion-diagnose-worker`. Each entry links to the maintained checklist, so updates to it apply to both agents.
73
+
74
+ The shared `.claude/settings.json` configures Claude Code. Codex uses the permissions of its own environment; these repository instructions do not grant filesystem access, network access or command approval. No Codex configuration change is required to read the instructions and skills.
75
+
76
+ For applications that install TotalFusion as a dependency, ask Codex to read `node_modules/totalfusion/AGENTS.md`; dependency instructions are not automatically loaded as application instructions. The repo-local skills are for a checkout of TotalFusion and are not shipped in its npm package.
77
+
78
+ See the official OpenAI documentation on [AGENTS.md](https://learn.chatgpt.com/docs/agent-configuration/agents-md) and [skills](https://learn.chatgpt.com/docs/build-skills) for discovery and invocation.
79
+
80
+ ## What is verified
81
+
82
+ `tests/agents.test.js` checks that the paths and the commands that `AGENTS.md` and the skills mention exist, that `llms.txt` lists every page and that its links lead to files that exist, that `llms-full.txt` is what the pages say, that the schemas have the same options as the code, and that the files for each agent lead to `AGENTS.md`. It also checks that every Codex skill has the same discovery metadata as its shared checklist and that its link resolves to that checklist. What is **not** verified is how a given assistant uses these files: that depends on the assistant.
@@ -0,0 +1 @@
1
+ <svg role="img" fill="#00ADD8" viewBox="0 5.285 24 13.44" xmlns="http://www.w3.org/2000/svg"><title>Go</title><path d="M1.811 10.231c-.047 0-.058-.023-.035-.059l.246-.315c.023-.035.081-.058.128-.058h4.172c.046 0 .058.035.035.07l-.199.303c-.023.036-.082.07-.117.07zM.047 11.306c-.047 0-.059-.023-.035-.058l.245-.316c.023-.035.082-.058.129-.058h5.328c.047 0 .07.035.058.07l-.093.28c-.012.047-.058.07-.105.07zm2.828 1.075c-.047 0-.059-.035-.035-.07l.163-.292c.023-.035.07-.07.117-.07h2.337c.047 0 .07.035.07.082l-.023.28c0 .047-.047.082-.082.082zm12.129-2.36c-.736.187-1.239.327-1.963.514-.176.046-.187.058-.34-.117-.174-.199-.303-.327-.548-.444-.737-.362-1.45-.257-2.115.175-.795.514-1.204 1.274-1.192 2.22.011.935.654 1.706 1.577 1.835.795.105 1.46-.175 1.987-.77.105-.13.198-.27.315-.434H10.47c-.245 0-.304-.152-.222-.35.152-.362.432-.97.596-1.274a.315.315 0 01.292-.187h4.253c-.023.316-.023.631-.07.947a4.983 4.983 0 01-.958 2.29c-.841 1.11-1.94 1.8-3.33 1.986-1.145.152-2.209-.07-3.143-.77-.865-.655-1.356-1.52-1.484-2.595-.152-1.274.222-2.419.993-3.424.83-1.086 1.928-1.776 3.272-2.02 1.098-.2 2.15-.07 3.096.571.62.41 1.063.97 1.356 1.648.07.105.023.164-.117.2m3.868 6.461c-1.064-.024-2.034-.328-2.852-1.029a3.665 3.665 0 01-1.262-2.255c-.21-1.32.152-2.489.947-3.529.853-1.122 1.881-1.706 3.272-1.95 1.192-.21 2.314-.095 3.33.595.923.63 1.496 1.484 1.648 2.605.198 1.578-.257 2.863-1.344 3.962-.771.783-1.718 1.273-2.805 1.495-.315.06-.63.07-.934.106zm2.78-4.72c-.011-.153-.011-.27-.034-.387-.21-1.157-1.274-1.81-2.384-1.554-1.087.245-1.788.935-2.045 2.033-.21.912.234 1.835 1.075 2.21.643.28 1.285.244 1.905-.07.923-.48 1.425-1.228 1.484-2.233z"/></svg>
@@ -0,0 +1 @@
1
+ <svg role="img" fill="#3776AB" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Python</title><path d="M14.25.18l.9.2.73.26.59.3.45.32.34.34.25.34.16.33.1.3.04.26.02.2-.01.13V8.5l-.05.63-.13.55-.21.46-.26.38-.3.31-.33.25-.35.19-.35.14-.33.1-.3.07-.26.04-.21.02H8.77l-.69.05-.59.14-.5.22-.41.27-.33.32-.27.35-.2.36-.15.37-.1.35-.07.32-.04.27-.02.21v3.06H3.17l-.21-.03-.28-.07-.32-.12-.35-.18-.36-.26-.36-.36-.35-.46-.32-.59-.28-.73-.21-.88-.14-1.05-.05-1.23.06-1.22.16-1.04.24-.87.32-.71.36-.57.4-.44.42-.33.42-.24.4-.16.36-.1.32-.05.24-.01h.16l.06.01h8.16v-.83H6.18l-.01-2.75-.02-.37.05-.34.11-.31.17-.28.25-.26.31-.23.38-.2.44-.18.51-.15.58-.12.64-.1.71-.06.77-.04.84-.02 1.27.05zm-6.3 1.98l-.23.33-.08.41.08.41.23.34.33.22.41.09.41-.09.33-.22.23-.34.08-.41-.08-.41-.23-.33-.33-.22-.41-.09-.41.09zm13.09 3.95l.28.06.32.12.35.18.36.27.36.35.35.47.32.59.28.73.21.88.14 1.04.05 1.23-.06 1.23-.16 1.04-.24.86-.32.71-.36.57-.4.45-.42.33-.42.24-.4.16-.36.09-.32.05-.24.02-.16-.01h-8.22v.82h5.84l.01 2.76.02.36-.05.34-.11.31-.17.29-.25.25-.31.24-.38.2-.44.17-.51.15-.58.13-.64.09-.71.07-.77.04-.84.01-1.27-.04-1.07-.14-.9-.2-.73-.25-.59-.3-.45-.33-.34-.34-.25-.34-.16-.33-.1-.3-.04-.25-.02-.2.01-.13v-5.34l.05-.64.13-.54.21-.46.26-.38.3-.32.33-.24.35-.2.35-.14.33-.1.3-.06.26-.04.21-.02.13-.01h5.84l.69-.05.59-.14.5-.21.41-.28.33-.32.27-.35.2-.36.15-.36.1-.35.07-.32.04-.28.02-.21V6.07h2.09l.14.01zm-6.47 14.25l-.23.33-.08.41.08.41.23.33.33.23.41.08.41-.08.33-.23.23-.33.08-.41-.08-.41-.23-.33-.33-.23-.41-.08-.41.08z"/></svg>
@@ -0,0 +1 @@
1
+ <svg role="img" fill="#CE412B" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Rust</title><path d="M23.8346 11.7033l-1.0073-.6236a13.7268 13.7268 0 00-.0283-.2936l.8656-.8069a.3483.3483 0 00-.1154-.578l-1.1066-.414a8.4958 8.4958 0 00-.087-.2856l.6904-.9587a.3462.3462 0 00-.2257-.5446l-1.1663-.1894a9.3574 9.3574 0 00-.1407-.2622l.49-1.0761a.3437.3437 0 00-.0274-.3361.3486.3486 0 00-.3006-.154l-1.1845.0416a6.7444 6.7444 0 00-.1873-.2268l.2723-1.153a.3472.3472 0 00-.417-.4172l-1.1532.2724a14.0183 14.0183 0 00-.2278-.1873l.0415-1.1845a.3442.3442 0 00-.49-.328l-1.076.491c-.0872-.0476-.1742-.0952-.2623-.1407l-.1903-1.1673A.3483.3483 0 0016.256.955l-.9597.6905a8.4867 8.4867 0 00-.2855-.086l-.414-1.1066a.3483.3483 0 00-.5781-.1154l-.8069.8666a9.2936 9.2936 0 00-.2936-.0284L12.2946.1683a.3462.3462 0 00-.5892 0l-.6236 1.0073a13.7383 13.7383 0 00-.2936.0284L9.9803.3374a.3462.3462 0 00-.578.1154l-.4141 1.1065c-.0962.0274-.1903.0567-.2855.086L7.744.955a.3483.3483 0 00-.5447.2258L7.009 2.348a9.3574 9.3574 0 00-.2622.1407l-1.0762-.491a.3462.3462 0 00-.49.328l.0416 1.1845a7.9826 7.9826 0 00-.2278.1873L3.8413 3.425a.3472.3472 0 00-.4171.4171l.2713 1.1531c-.0628.075-.1255.1509-.1863.2268l-1.1845-.0415a.3462.3462 0 00-.328.49l.491 1.0761a9.167 9.167 0 00-.1407.2622l-1.1662.1894a.3483.3483 0 00-.2258.5446l.6904.9587a13.303 13.303 0 00-.087.2855l-1.1065.414a.3483.3483 0 00-.1155.5781l.8656.807a9.2936 9.2936 0 00-.0283.2935l-1.0073.6236a.3442.3442 0 000 .5892l1.0073.6236c.008.0982.0182.1964.0283.2936l-.8656.8079a.3462.3462 0 00.1155.578l1.1065.4141c.0273.0962.0567.1914.087.2855l-.6904.9587a.3452.3452 0 00.2268.5447l1.1662.1893c.0456.088.0922.1751.1408.2622l-.491 1.0762a.3462.3462 0 00.328.49l1.1834-.0415c.0618.0769.1235.1528.1873.2277l-.2713 1.1541a.3462.3462 0 00.4171.4161l1.153-.2713c.075.0638.151.1255.2279.1863l-.0415 1.1845a.3442.3442 0 00.49.327l1.0761-.49c.087.0486.1741.0951.2622.1407l.1903 1.1662a.3483.3483 0 00.5447.2268l.9587-.6904a9.299 9.299 0 00.2855.087l.414 1.1066a.3452.3452 0 00.5781.1154l.8079-.8656c.0972.0111.1954.0203.2936.0294l.6236 1.0073a.3472.3472 0 00.5892 0l.6236-1.0073c.0982-.0091.1964-.0183.2936-.0294l.8069.8656a.3483.3483 0 00.578-.1154l.4141-1.1066a8.4626 8.4626 0 00.2855-.087l.9587.6904a.3452.3452 0 00.5447-.2268l.1903-1.1662c.088-.0456.1751-.0931.2622-.1407l1.0762.49a.3472.3472 0 00.49-.327l-.0415-1.1845a6.7267 6.7267 0 00.2267-.1863l1.1531.2713a.3472.3472 0 00.4171-.416l-.2713-1.1542c.0628-.0749.1255-.1508.1863-.2278l1.1845.0415a.3442.3442 0 00.328-.49l-.49-1.076c.0475-.0872.0951-.1742.1407-.2623l1.1662-.1893a.3483.3483 0 00.2258-.5447l-.6904-.9587.087-.2855 1.1066-.414a.3462.3462 0 00.1154-.5781l-.8656-.8079c.0101-.0972.0202-.1954.0283-.2936l1.0073-.6236a.3442.3442 0 000-.5892zm-6.7413 8.3551a.7138.7138 0 01.2986-1.396.714.714 0 11-.2997 1.396zm-.3422-2.3142a.649.649 0 00-.7715.5l-.3573 1.6685c-1.1035.501-2.3285.7795-3.6193.7795a8.7368 8.7368 0 01-3.6951-.814l-.3574-1.6684a.648.648 0 00-.7714-.499l-1.473.3158a8.7216 8.7216 0 01-.7613-.898h7.1676c.081 0 .1356-.0141.1356-.088v-2.536c0-.074-.0536-.0881-.1356-.0881h-2.0966v-1.6077h2.2677c.2065 0 1.1065.0587 1.394 1.2088.0901.3533.2875 1.5044.4232 1.8729.1346.413.6833 1.2381 1.2685 1.2381h3.5716a.7492.7492 0 00.1296-.0131 8.7874 8.7874 0 01-.8119.9526zM6.8369 20.024a.714.714 0 11-.2997-1.396.714.714 0 01.2997 1.396zM4.1177 8.9972a.7137.7137 0 11-1.304.5791.7137.7137 0 011.304-.579zm-.8352 1.9813l1.5347-.6824a.65.65 0 00.33-.8585l-.3158-.7147h1.2432v5.6025H3.5669a8.7753 8.7753 0 01-.2834-3.348zm6.7343-.5437V8.7836h2.9601c.153 0 1.0792.1772 1.0792.8697 0 .575-.7107.7815-1.2948.7815zm10.7574 1.4862c0 .2187-.008.4363-.0243.651h-.9c-.09 0-.1265.0586-.1265.1477v.413c0 .973-.5487 1.1846-1.0296 1.2382-.4576.0517-.9648-.1913-1.0275-.4717-.2704-1.5186-.7198-1.8436-1.4305-2.4034.8817-.5599 1.799-1.386 1.799-2.4915 0-1.1936-.819-1.9458-1.3769-2.3153-.7825-.5163-1.6491-.6195-1.883-.6195H5.4682a8.7651 8.7651 0 014.907-2.7699l1.0974 1.151a.648.648 0 00.9182.0213l1.227-1.1743a8.7753 8.7753 0 016.0044 4.2762l-.8403 1.8982a.652.652 0 00.33.8585l1.6178.7188c.0283.2875.0425.577.0425.8717zm-9.3006-9.5993a.7128.7128 0 11.984 1.0316.7137.7137 0 01-.984-1.0316zm8.3389 6.71a.7107.7107 0 01.9395-.3625.7137.7137 0 11-.9405.3635z"/></svg>
@@ -0,0 +1 @@
1
+ <svg role="img" fill="#654FF0" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>WebAssembly</title><path d="M14.745,0c0,0.042,0,0.085,0,0.129c0,1.52-1.232,2.752-2.752,2.752c-1.52,0-2.752-1.232-2.752-2.752 c0-0.045,0-0.087,0-0.129H0v24h24V0H14.745z M11.454,21.431l-1.169-5.783h-0.02l-1.264,5.783H7.39l-1.824-8.497h1.59l1.088,5.783 h0.02l1.311-5.783h1.487l1.177,5.854h0.02l1.242-5.854h1.561l-2.027,8.497H11.454z M20.209,21.431l-0.542-1.891h-2.861l-0.417,1.891 h-1.59l2.056-8.497h2.509l2.5,8.497H20.209z M17.812,15.028l-0.694,3.118h2.159l-0.796-3.118H17.812z"/></svg>
@@ -0,0 +1,60 @@
1
+ # Binary data
2
+
3
+ `Buffer`, `Uint8Array`, `ArrayBuffer` and the typed arrays (`Float32Array`, `Float64Array`, `Int32Array`, ...) travel as raw bytes next to the JSON, anywhere in the arguments or in the result. No base64, no JSON array of numbers, and the bytes are not copied when the frame is built.
4
+
5
+ ```js
6
+ const image = await fs.promises.readFile('photo.jpg');
7
+ const result = await fusion.python('vision.resize', { image, width: 256 }); // result.image is a Buffer
8
+ ```
9
+
10
+ ```python
11
+ def resize(data):
12
+ picture = Image.open(io.BytesIO(data['image'])) # data['image'] is bytes
13
+ ...
14
+ return { 'image': output.getvalue() } # bytes -> Buffer
15
+
16
+ def normalize(data):
17
+ values = np.frombuffer(data['values'], dtype=np.float32) # Float32Array -> memoryview, no copy
18
+ return (values - values.mean()) / values.std() # numpy array -> Float32Array
19
+ ```
20
+
21
+ | JavaScript | Python |
22
+ |---|---|
23
+ | `Buffer`, `Uint8Array`, `ArrayBuffer` | `bytes` |
24
+ | `Int8Array`, `Int16Array`, `Uint16Array`, `Int32Array`, `Uint32Array`, `Float32Array`, `Float64Array`, `BigInt64Array`, `BigUint64Array` | `memoryview` of the matching type (read-only, no copy) |
25
+
26
+ From Python, `bytes`, `bytearray`, `memoryview`, `array.array` and anything with the buffer protocol (NumPy arrays included) arrive as a `Buffer` (bytes) or the matching typed array. Notes:
27
+
28
+ - Arrays are sent **flat**: the shape of a multi-dimensional NumPy array is not transmitted. Send it as another field (`{ data, shape }`) if you need it.
29
+ - Typed arrays are little-endian, like every platform Node.js and CPython run on (x64 and ARM64). Big-endian buffers coming from Python (NumPy `>f4`) are converted for you.
30
+ - Types without a JavaScript typed array (`float16`, complex numbers) arrive as raw bytes in a `Buffer`, as do boolean arrays.
31
+ - Non-contiguous NumPy arrays (slices with a step, transposes) are sent in C order.
32
+ - `"$bin"` is a reserved key and cannot be used in your data.
33
+ - A frame can carry up to 512 MB in total, of which at most 64 MB can be JSON.
34
+ - Measured against sending the same bytes as base64 inside JSON: 1 MB in 0.5 ms instead of 4.4 ms, 32 MB in 14 ms instead of 145 ms, and a 100 MB buffer (133 MB as base64, over the JSON limit) in 43 ms.
35
+
36
+ ## In Rust
37
+
38
+ A Rust worker sends and receives the same data, as the vectors of the matching type:
39
+
40
+ | JavaScript | Rust (`Value`) |
41
+ |---|---|
42
+ | `Buffer`, `Uint8Array`, `ArrayBuffer` | `Value::Bytes(Vec<u8>)`, read with `as_bytes()` |
43
+ | `Float32Array`, `Float64Array` | `Value::F32`, `Value::F64`, read with `as_f32s()`, `as_f64s()` |
44
+ | `Int32Array` | `Value::I32`, read with `as_i32s()` |
45
+ | `Int8Array`, `Int16Array`, `Uint16Array`, `Uint32Array`, `BigInt64Array`, `BigUint64Array` | `Value::I8`, `I16`, `U16`, `U32`, `I64`, `U64` |
46
+
47
+ Returning a `Vec<u8>` or a `Vec<f32>` (they convert into a `Value`) sends a `Buffer` or a `Float32Array` back. The bytes arrive in Rust as a vector (a copy of the frame, one `memcpy`), not as a view. NaN and infinity cannot be sent (JSON has no such numbers): the call fails with `NOT_SERIALIZABLE`. The crate is described in [rust/README.md](../rust/README.md).
48
+
49
+ ## In Go
50
+
51
+ A Go worker sends and receives the same data, as the slices of the matching type:
52
+
53
+ | JavaScript | Go |
54
+ |---|---|
55
+ | `Buffer`, `Uint8Array`, `ArrayBuffer` | `[]byte`, read with `AsBytes()` |
56
+ | `Float32Array`, `Float64Array` | `[]float32`, `[]float64`, read with `AsFloat32s()`, `AsFloat64s()` |
57
+ | `Int32Array` | `[]int32`, read with `AsInt32s()` |
58
+ | `Int8Array`, `Int16Array`, `Uint16Array`, `Uint32Array`, `BigInt64Array`, `BigUint64Array` | `[]int8`, `[]int16`, `[]uint16`, `[]uint32`, `[]int64`, `[]uint64`, read with `Raw()` |
59
+
60
+ Returning a `[]byte` or a `[]float32` sends a `Buffer` or a `Float32Array` back. A `[]byte` that arrives is a slice of the frame (no copy). NaN and infinity cannot be sent: the call fails with `NOT_SERIALIZABLE`. A struct or a `[]string` is sent as JSON. The module is described in [go/README.md](../go/README.md).