[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-76260":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":12,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":14,"forks30d":14,"starsTrendScore":18,"compositeScore":19,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":9,"pushedAt":9,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":14,"starSnapshotCount":14,"syncStatus":15,"lastSyncTime":27,"discoverSource":28},76260,"machinen.dev","redwoodjs\u002Fmachinen.dev","redwoodjs","Pause, resume, fork Linux VMs across hosts",null,"TypeScript",135,1,101,0,2,5,31,7,47.5,false,"main",true,[],"2026-06-12 04:01:21","\u003Cp align=\"center\">\n  \u003Cimg src=\".\u002Fdocs\u002Flogo.svg\" alt=\"machinen\" \u002F>\n\u003C\u002Fp>\n\n\u003Ch1 align=\"center\">M A C H I N E N\u003C\u002Fh1>\n\nHand off a running Linux VM between hosts. Freeze it on your laptop, thaw it\non a server, resume it next week. The program picks up exactly where it left\noff — like waking a laptop from sleep, except on a different computer.\n\nA native arm64 microVM runtime under the hood. Node.js is the first-class\ntarget; Python, bash, and anything else that boots in a Linux VM works too.\n\n> **Note:** the source code isn't published yet — it'll be available here soon.\n\n## Install\n\n```bash\nnpm i @machinen\u002Fcli @machinen\u002Fruntime\n```\n\nThen run the CLI with `npx machinen …` (or the shorter `npx mn …` — both\nnames install). Prefer it on your PATH? `npm i -g @machinen\u002Fcli` is fine\ntoo.\n\nThe right VMM binary is pulled automatically via optional dependencies\n(`@machinen\u002Fvmm-arm64-darwin` on Apple Silicon Macs, `@machinen\u002Fvmm-arm64-linux`\non arm64 Linux). No system dependencies.\n\nFirst run fetches the kernel + rootfs from a Github release on the\ncompanion repo over plain HTTPS — no auth required.\n\n## Quickstart\n\nBake an image, boot it, accumulate some state, then move the running process\nto another host.\n\n### 1. Bake\n\nA tiny HTTP server that counts hits in memory:\n\n```js\n\u002F\u002F counter.mjs\nimport { createServer } from \"node:http\";\nlet count = 0;\ncreateServer((_, res) => {\n  res.end(JSON.stringify({ count: ++count }) + \"\\n\");\n}).listen(3000);\n```\n\nBake it into a rootfs tarball with `provision()`:\n\n```ts\n\u002F\u002F bake.ts\nimport { readFileSync } from \"node:fs\";\nimport { provision } from \"@machinen\u002Fruntime\";\n\nawait provision({\n  install: async (vm) => {\n    await vm.exec(\"apt-get update && apt-get install -y nodejs\");\n    await vm.writeFile(\"\u002Fopt\u002Fcounter.mjs\", readFileSync(\".\u002Fcounter.mjs\"));\n  },\n  cmd: [\"\u002Fusr\u002Fbin\u002Fnode\", \"\u002Fopt\u002Fcounter.mjs\"],\n  out: \".\u002Fcounter.tar.gz\",\n});\n```\n\n```bash\nnode bake.ts\n```\n\n### 2. Boot\n\n```bash\nnpx machinen boot --name counter -p 3000:3000 --detached .\u002Fcounter.tar.gz\ncurl localhost:3000                        # { count: 1 }\ncurl localhost:3000                        # { count: 2 }\n```\n\nThe process is now sitting on host A with `count = 2` in its heap.\n\n### 3. Handoff\n\nFreeze it, copy the bundle to host B, thaw it:\n\n```bash\nnpx machinen snapshot counter .\u002Fcounter.snap\nscp .\u002Fcounter.tar.gz .\u002Fcounter.snap host-b:\nssh host-b npx machinen restore .\u002Fcounter.snap -p 3000:3000 &\ncurl host-b:3000                           # { count: 3 }  ← same process\n```\n\nSame arch only (arm64 ↔ arm64). Memory, file descriptors, and timers come\nback exactly as they were.\n\nThe bundle remembers the absolute path of the rootfs tarball you booted\nfrom. On the same host that's all you need — `restore` reuses the same\ntarball so CRIU can re-open file-backed VMAs (executable, shared\nlibraries) at the paths they were dumped from. Across hosts, copy the\ntarball to the same path or pass `--image \u003Ctarball>` to override.\n\n## Fork\n\n`fork` is snapshot + restore without killing the source. The original keeps\nrunning; you get a sibling VM with the same heap, same open files, and a\ncopy-on-write disk. Both processes diverge from the same instant.\n\nPick up from Step 2 above — `counter` is running with `count = 2`:\n\n```bash\nnpx machinen fork counter --new-name counter-b --detach\n\nnpx machinen exec counter   -- curl -s localhost:3000   # { count: 3 }\nnpx machinen exec counter-b -- curl -s localhost:3000   # { count: 3 }\nnpx machinen exec counter-b -- curl -s localhost:3000   # { count: 4 }\nnpx machinen exec counter   -- curl -s localhost:3000   # { count: 4 }\n```\n\nBoth VMs branched from the same `count = 2` heap and now count\nindependently. Use it to clone a warmed-up process: a database with caches\nloaded, a test fixture in exactly the right state, a long-running compute\njob branched into N parallel explorations.\n\nThe fork doesn't inherit the source's `-p` host forwards — host ports are\nglobal, only one process can bind each one. Two ways to reach a fork:\n\n```bash\n# A) exec over vsock — works for any guest port, no host forward needed.\nnpx machinen exec counter-b -- curl -s localhost:3000\n\n# B) -p with non-conflicting host ports — forwards on the host.\nnpx machinen fork counter --new-name counter-b -p 3001:3000 --detach\ncurl localhost:3001                                            # the fork\ncurl localhost:3000                                            # still the source\n```\n\nPass `-p` multiple times for multiple ports. If you pick a host port the\nsource is already forwarding, `fork` errors with\n`BOOT_PORT_FORWARD_IN_USE` and names the VM that's holding it.\n\nFrom Node, same shape:\n\n```ts\nconst fork = await vm.fork({ name: \"counter-b\" });\n```\n\n## From Node\n\nSame arc, driven from TypeScript:\n\n```ts\nimport { readFileSync } from \"node:fs\";\nimport { boot, provision, restore } from \"@machinen\u002Fruntime\";\n\nawait provision({\n  install: async (vm) => {\n    await vm.exec(\"apt-get install -y nodejs\");\n    await vm.writeFile(\"\u002Fopt\u002Fcounter.mjs\", readFileSync(\".\u002Fcounter.mjs\"));\n  },\n  cmd: [\"\u002Fusr\u002Fbin\u002Fnode\", \"\u002Fopt\u002Fcounter.mjs\"],\n  out: \".\u002Fcounter.tar.gz\",\n});\n\nconst vm = await boot({ image: \".\u002Fcounter.tar.gz\", name: \"counter\" });\n\u002F\u002F ... let it run, serve traffic, accumulate state ...\n\nawait vm.snapshot({ outDir: \".\u002Fcounter.snap\" });\n\n\u002F\u002F elsewhere (possibly on another host):\nconst restored = await restore({ snapDir: \".\u002Fcounter.snap\" });\n```\n\n## Documentation\n\n- [Quickstart](.\u002Fdocs\u002Fquickstart.md) — the same three-step walkthrough\n  with more colour\n- [Guides](.\u002Fdocs\u002F) — recipes for creating VMs, snapshots and forks,\n  mounts, and networking\n- [`@machinen\u002Fcli` reference](.\u002Fdocs\u002Fapi\u002Fcli.md) — every command\n  and flag\n- [`@machinen\u002Fruntime` reference](.\u002Fdocs\u002Fapi\u002Fruntime.md) — every\n  exported function, type, and error class (typedoc-generated)\n\nThree runnable demos live in [`examples\u002F`](.\u002Fexamples):\n\n- [`quickstart`](.\u002Fexamples\u002Fquickstart) — the counter walkthrough above\n  as a runnable repo.\n- [`fork-pi`](.\u002Fexamples\u002Ffork-pi) — snapshot a VM with the `pi` coding\n  agent installed, then fork three siblings that each answer a different\n  prompt in parallel.\n- [`live-mount`](.\u002Fexamples\u002Flive-mount) — host directory mounted into\n  the guest over an in-VMM virtio-fs device; bidirectional, no rebuild\n  on edit.\n\n## Other ways to boot\n\n```bash\nnpx machinen boot -- \u002Fbin\u002Fsh                    # ad-hoc: boot base + run a cmd\nnpx machinen boot .\u002Fmy-image.tar.gz             # boot a provisioned rootfs tarball\nnpx machinen install                            # pre-fetch base assets (CI \u002F airgap)\nnpx machinen install --version \u003Ctag>            # pin to a specific release tag\n```\n\n## License\n\n[FSL-1.1-MIT](https:\u002F\u002Ffsl.software\u002F) — Functional Source License. Converts to MIT two\nyears after each release.\n","Machinen 是一个用于在不同主机之间暂停、恢复和迁移正在运行的 Linux 虚拟机的工具。它支持将虚拟机从一台主机冻结并迁移到另一台主机，确保虚拟机在新的主机上恢复后能从上次停止的地方继续运行。该项目使用 TypeScript 开发，并基于 arm64 架构的微虚拟机运行时环境，特别适合 Node.js 应用程序，同时也支持 Python、bash 以及其他能在 Linux 虚拟机中运行的应用。Machinen 无需系统依赖项，通过 npm 安装即可使用，非常适合需要跨设备或跨云平台迁移开发环境与测试场景的开发者。","2026-06-11 03:54:48","CREATED_QUERY"]