clusterflux-public/disasmer_spec.md
Disasmer release dry run f22d0a5791 Public dry run dryrun-309831e1e021
Source commit: 309831e1e021f962c118452336776fd9a94025f9

Public tree identity: sha256:6fa95c1745579bd6256dbeb3d476db0b07c2f24aa9213b0f7783ce1adfc8aca5
2026-07-03 16:07:13 +02:00

1437 lines
31 KiB
Markdown

# Disasmer Specification
**Status:** draft design spec
**Name:** Disasmer, short for **distributed Wasm**. The name intentionally sounds a bit like Wasmer and a bit like “disaster.”
**Primary goal:** make distributed execution feel like normal multithreaded programming and normal source-level debugging.
Disasmer is a distributed WebAssembly runtime that lets multiple real machines behave like one logical machine. A program runs as one **Virtual Process** with many **Virtual Threads**. Each virtual thread runs on exactly one real machine at a time, but different virtual threads, memory spaces, filesystems, and build tasks may live on different machines.
The core promise:
```text
Developers debug Disasmer programs like ordinary multithreaded programs.
The runtime handles the distributed reality underneath.
```
Disasmer is also intended to support a build-system use case: one build is a virtual process, and build steps are virtual threads/tasks that may run in containers or Nix-defined environments on different operating systems and architectures.
---
## 1. Goals
Disasmer should provide:
```text
distributed Wasm execution
normal VS Code debugging
virtual threads across machines
distributed/sharded memory spaces
cluster-wide suspend/resume
per-thread virtual filesystems
container/Nix-backed execution environments
single-source-file distributed builds
explicit artifact publication
low-latency reliable control-plane coordination
```
The debugger should see:
```text
one process
many threads
normal stacks
normal locals
normal source files
normal breakpoints
normal memory inspection
```
The optional Disasmer inspector may expose distributed internals, but the default debugging experience should remain normal.
---
## 2. Non-goals for the MVP
The MVP should not attempt:
```text
transparent raw remote pointers
live hot-swapping arbitrary Wasm/Rust stack frames
checkpointing live sockets
checkpointing arbitrary external OS state
consensus on every memory access
eagerly copying every byte of cluster memory on each breakpoint
transparent survival of lost non-replicated nodes
full Kubernetes/CI-platform replacement semantics
```
The MVP should favor simple, explicit, debuggable semantics over maximum transparency.
---
## 3. Core terminology
```text
Cluster
A set of real (or virtual) machines participating in one Disasmer runtime.
Coordinator
The control-plane entry point for the cluster.
Usually reachable through DNS, e.g. cluster.example.com.
Node
A real machine participating in the cluster.
Node Runtime
The Disasmer runtime process running on a node.
It hosts virtual threads/tasks, memory shards, filesystem data, debug services,
environment caches, and node-to-node communication.
Virtual Process
The logical process seen by the program and debugger.
Internally, it may span many nodes.
Virtual Thread
A debugger-visible logical execution unit.
For ordinary Disasmer programs, this is usually a Wasm execution context.
For build-system use, it may be backed by a containerized process, sandboxed task,
or platform-specific build command.
Virtual Task
Synonym for Virtual Thread when the unit of work is task-like rather than
thread-like. The debugger still sees it as a thread.
Memory Space
A logical addressable memory region.
It may be owned by any node and accessed remotely by other threads.
Filesystem Overlay
A per-thread writable virtual filesystem layer.
Environment Resource
A Containerfile, Dockerfile, Nix flake, or equivalent project resource that
defines where and how a virtual thread/task should run.
Disasmer Bundle / Virtual Binary
The packaged executable artifact containing Wasm modules, manifests, debug
metadata, environment definitions, and selected input files.
Checkpoint
A saved execution image containing enough state to resume a virtual thread.
Debug Epoch
A globally coordinated stopped state used for debugging.
```
---
## 4. High-level architecture
```text
VS Code / Debugger
-> DAP / LLDB / custom Disasmer debug adapter
-> Disasmer debug endpoint
-> Coordinator
-> Node Runtimes
```
Cluster connectivity:
```text
new node starts
-> connects to coordinator through DNS
-> authenticates
-> receives membership/configuration
-> establishes peer links to other nodes
```
Node-to-node communication should prefer:
```text
QUIC direct link
-> NAT punching where possible
-> relay fallback if direct connectivity fails
```
The coordinator is not a hypervisor. It is the **cluster control plane**. It manages membership, identity, placement, debug epochs, metadata, and failure decisions. The data plane should be mostly direct node-to-node traffic.
---
## 5. Project layout and resource discovery
Disasmer should make environment resources and input files first-class project resources.
Example project:
```text
my-project/
src/
main.rs
Cargo.toml
Cargo.lock
envs/
linux/Containerfile
windows/Containerfile
macos/flake.nix
macos/flake.lock
inputs/
config.json
schema.sql
test-data/
example-a.txt
example-b.txt
disasmer.toml # optional; used only for overrides/disambiguation
```
Default discovery rules:
```text
envs/<name>/Containerfile
-> defines environment <name> of kind container
envs/<name>/Dockerfile
-> defines environment <name> of kind container
envs/<name>/flake.nix
-> defines environment <name> of kind nix-flake
inputs/**
-> included in the bundle's default VFS seed
src/**, Cargo.toml, Cargo.lock
-> included for reproducible debugging/building when configured
```
The source code should be able to reference discovered environments by name:
```rust
env!("linux")
env!("windows")
env!("macos")
```
Adding this file:
```text
envs/linux/Containerfile
```
should make this possible in source:
```rust
spawn::task(compile).env(env!("linux"))
```
No image name, host VM, registry, CI runner, or YAML platform configuration should be required in the source code.
---
## 6. Environment resources
An **Environment Resource** defines the execution environment for a virtual thread/task.
Supported MVP environment kinds:
```text
container
Built from Containerfile or Dockerfile.
Produces or references an OCI-compatible image or equivalent runtime image.
nix-flake
Resolved from flake.nix and flake.lock.
Produces a reproducible command environment, dev shell, package closure, or
runtime root depending on project configuration.
```
Containerfiles and Nix flakes are not identical concepts. Disasmer treats both as ways to produce a normalized **Execution Environment**:
```text
Execution Environment
name
kind
digest
platform constraints
runtime capabilities
build/resolution recipe
cached materialized form on capable nodes
```
Example normalized environments:
```text
environment linux
kind: container
recipe: envs/linux/Containerfile
context: envs/linux
digest: sha256:...
requires: os=linux, arch=x86_64
environment macos
kind: nix-flake
recipe: envs/macos/flake.nix
lock: envs/macos/flake.lock
digest: sha256:...
requires: os=macos, arch=arm64
```
Environment materialization should be cached on nodes:
```text
environment digest -> local image / Nix store path / sandbox root
```
The virtual binary should not embed full container images by default. It should embed recipes, manifests, hashes, lock files, and selected context files. Full vendoring should be an explicit mode:
```text
disasmer build --vendor-envs
```
Possible vendored data:
```text
OCI layers
Nix closure
prebuilt environment archive
```
---
## 7. Disasmer bundle / virtual binary
A Disasmer bundle is the packaged executable artifact.
It contains:
```text
Wasm module(s)
Wasm component metadata
source maps / DWARF / debug metadata
Disasmer manifest
environment resource manifests
selected environment recipe files
selected environment context files
selected VFS seed files
source snapshot when enabled
content hashes
capability declarations
```
Conceptual bundle layout:
```text
app.dis
/modules/main.wasm
/debug/main.dwarf
/manifest/disasmer.json
/envs/linux/Containerfile
/envs/windows/Containerfile
/envs/macos/flake.nix
/envs/macos/flake.lock
/inputs/config.json
/inputs/schema.sql
/inputs/test-data/**
/source/src/main.rs
/source/Cargo.toml
/source/Cargo.lock
```
The bundle is content-addressed where possible. Every resource that affects execution should contribute to the bundle digest.
The coordinator schedules bundles, not loose files.
---
## 8. Execution model
A Disasmer application runs as one **Virtual Process**.
A virtual process contains:
```text
virtual threads/tasks
memory spaces
filesystem overlays
runtime metadata
debug metadata
checkpoint metadata
environment bindings
```
Each virtual thread runs on exactly one node at a time:
```text
thread T1 -> node A
thread T2 -> node B
thread T3 -> node C
```
A virtual thread may be implemented as:
```text
Wasm execution context
containerized process
sandboxed native process
platform-specific build command
```
The debugger sees all of these as threads in one virtual process.
Thread placement is based on environment requirements:
```text
spawn task with env!("linux")
-> coordinator finds a node that can materialize/run environment linux
-> node runtime starts the task
```
The source code selects logical environments, not specific machines:
```rust
env!("linux") // logical environment
```
Not:
```rust
node("builder-17") // real machine, generally not wanted in portable source
```
---
## 9. Virtual filesystem model
Each virtual thread/task receives a virtual filesystem.
Default mount model:
```text
/vfs/project
Read-only source/input snapshot from the bundle.
/vfs/work
Per-thread writable copy-on-write overlay.
/vfs/artifacts
Published artifact namespace.
/vfs/shared
Optional shared namespace with explicit synchronization rules.
```
A thread can create and modify files in its writable overlay.
File creation:
```text
Thread T creates file F
-> T owns the writable version of F
-> bytes are physically stored on T's current node by default
```
Flush:
```text
fs::flush()
-> closes the current write epoch
-> publishes filesystem changes
-> makes changes visible according to VFS consistency rules
```
Sync:
```text
fs::sync()
-> makes selected published changes durable/replicated
```
Important distinction:
```text
flush = visibility / synchronization point
sync = durability / replication point
```
Suspend implicitly performs:
```text
flush()
checkpoint_thread()
optionally sync()
```
Git-like analogy:
```text
working tree = thread-local filesystem overlay
commit = flush point
object store = chunk/blob storage
branch/head = latest visible version
```
Disasmer does not need to literally use Git. A content-addressed chunk store is a better internal primitive.
---
## 10. Memory model
Disasmer memory is divided into **Memory Spaces**.
A memory space has:
```text
stable virtual identity
address range or handle
current owner node
version/epoch metadata
optional cached pages
optional replicas
```
Allocation policy:
```text
Memory allocated by a virtual thread is placed on that thread's current node by default.
```
Example:
```text
thread T1 running on node A allocates memory M1
-> M1 initially owned by node A
thread T2 running on node B allocates memory M2
-> M2 initially owned by node B
```
Remote access is allowed, but mediated by Disasmer.
The MVP should not make ordinary raw pointers transparently remote. Instead, distributed state should use explicit Disasmer handles/types:
```rust
DBox<T>
DArc<T>
DMutex<T>
DVec<T>
DAtomicU64
```
Local state remains normal language state:
```rust
Vec<T> // local to one Wasm context/thread
DVec<T> // distributed memory object
std::sync::Mutex<T> // local/node/thread concept
disasmer::sync::DMutex<T> // distributed synchronization primitive
```
The debugger sees a coherent virtual memory model. Internally, Disasmer maps:
```text
virtual memory reference
-> memory space
-> owner node
-> page/chunk
-> epoch
```
---
## 11. Synchronization and consensus
The programming model should feel close to normal thread safety:
```text
locks
atomics
happens-before
shared mutable memory
race conditions
linearizable operations
```
The distributed runtime still needs distributed-systems machinery underneath.
Consensus/control-plane coordination is used for:
```text
cluster membership
node identity
debug epochs
memory ownership metadata
thread placement metadata
checkpoint ownership
filesystem version metadata
failure decisions
```
Consensus should not be on the hot path for every load/store.
Preferred split:
```text
Control plane:
consensus-backed metadata
Data plane:
direct QUIC/RPC between node runtimes
owner-based memory protocol
leases
fencing tokens
copy-on-write pages/chunks
```
Every sensitive operation should carry an epoch or fencing token:
```text
remote_load(addr, epoch)
remote_store(addr, epoch)
transfer_memory_owner(space, node, epoch)
migrate_thread(thread, node, epoch)
debug_freeze(epoch)
resume(epoch)
```
---
## 12. Suspend / resume / checkpoint
Disasmer supports suspending a virtual thread.
User-facing operation:
```rust
suspend().await?
```
Semantics:
```text
1. Reach a safepoint.
2. Stop the virtual thread.
3. Flush the thread filesystem overlay.
4. Snapshot Wasm execution state.
5. Snapshot or reference stack/heap/memory pages.
6. Store checkpoint metadata.
7. Mark thread as PARKED.
```
Resume:
```rust
thread.resume().await?
```
Semantics:
```text
1. Select a target node.
2. Fetch checkpoint metadata.
3. Restore Wasm execution state.
4. Restore/mount filesystem overlay.
5. Reconnect memory spaces.
6. Continue execution from a safepoint.
```
The coordinator should store checkpoint metadata, not necessarily all bytes.
Actual checkpoint data should live in:
```text
node-local storage
replicated storage
content-addressed blob storage
object storage
peer-to-peer transferred chunks
```
This enables:
```text
thread migration
hibernation
debug pause/resume
load balancing
manual relocation
fault recovery when state is replicated
```
---
## 13. Debugging model
Debuggability is a primary design requirement.
Recommended external interface:
```text
VS Code
-> DAP
-> LLDB / lldb-dap or custom Disasmer adapter
-> Disasmer debug endpoint
-> Coordinator
-> Node Runtimes
```
Disasmer should present the cluster as one virtual debug target.
When a breakpoint is hit:
```text
1. A virtual thread hits a breakpoint or trap.
2. Coordinator creates a new Debug Epoch.
3. All node runtimes stop guest execution at safepoints.
4. Memory ownership/migration is frozen.
5. Thread states are collected.
6. Memory pages are pinned copy-on-write.
7. Filesystem overlay versions are pinned.
8. Debugger is told that all threads are stopped.
```
Debugger memory access should be served from a coherent snapshot.
Collect eagerly:
```text
thread states
stacks
locals
globals
memory maps
filesystem manifests
```
Collect lazily:
```text
heap pages
large memory regions
filesystem chunks
container logs beyond recent tail
large artifact data
```
The debugger illusion:
```text
Debugger thinks:
process P is stopped
Reality:
cluster is stopped at Debug Epoch E
```
Optional Disasmer inspector:
```text
thread -> node
thread -> environment
memory space -> owner node
file -> overlay version
artifact -> producer task
environment -> digest/cache state
remote calls
page migrations
lock wait graph
checkpoint state
consensus/control-plane state
```
The default debugger view should remain normal.
---
## 14. VS Code UX
Disasmer should provide a VS Code extension.
The extension should:
```text
watch envs/**/Containerfile
watch envs/**/Dockerfile
watch envs/**/flake.nix
watch envs/**/flake.lock
watch inputs/**
watch src/**
run disasmer build before debugging
start or attach to a virtual process
bind breakpoints to Wasm/source debug info
show virtual threads in the normal debugger thread list
show stdout/stderr per virtual thread/task
show VFS/artifact state in an optional panel
show environment resources as first-class project items
provide autocomplete/diagnostics for env!("...") references
```
The intended UX:
```text
1. Add envs/linux/Containerfile.
2. VS Code detects environment "linux".
3. Source autocomplete now accepts env!("linux").
4. Press F5.
5. Disasmer builds the virtual binary.
6. Disasmer starts the virtual process.
7. VS Code attaches to it as one normal debug target.
8. Breakpoints work across virtual threads/tasks.
```
The extension may generate editor metadata:
```text
target/disasmer/generated/envs.rs
target/disasmer/generated/resources.json
```
But this generated metadata should not be hand-edited.
The project should not require YAML for ordinary usage.
Optional `disasmer.toml` may exist for overrides:
```toml
[envs.linux]
path = "envs/linux/Containerfile"
requires = { os = "linux", arch = "x86_64" }
[vfs]
include = ["inputs/**", "src/**", "Cargo.toml", "Cargo.lock"]
exclude = ["target/**", ".git/**"]
```
---
## 15. Editing source while debugging
Disasmer should support a fast edit/restart/debug loop.
MVP behavior:
```text
source edit
-> rebuild bundle
-> restart selected virtual task/thread from a clean boundary
-> reattach/rebind breakpoints
```
The MVP should not hot-swap arbitrary live code into existing stack frames.
Supported restart boundaries:
```text
task entrypoint
last explicit task checkpoint
last published filesystem state
last clean build input snapshot
```
Useful VS Code commands:
```text
Disasmer: Restart Selected Virtual Thread
Disasmer: Restart Failed Task
Disasmer: Restart From Last Flush
Disasmer: Restart Whole Virtual Process
Disasmer: Rebuild Bundle And Rebind Breakpoints
```
Semantics for restarting a selected task:
```text
1. Save source changes.
2. Rebuild the Disasmer bundle.
3. Stop the selected virtual thread/task.
4. Discard unflushed task-local filesystem changes unless configured otherwise.
5. Start the task again using the new bundle version.
6. Mount the same declared environment.
7. Mount the same input/VFS seed or chosen checkpoint boundary.
8. Rebind breakpoints using new debug metadata.
```
The runtime may keep the rest of the virtual process alive only if compatibility checks pass:
```text
same public task signatures
same serialized argument schema
compatible resource manifest
compatible memory/handle ABI
```
If compatibility checks fail, the extension should restart the whole virtual process.
Design rule:
```text
Task restart is an MVP feature.
Live code hot-swap is not.
```
---
## 16. Rust as the primary source language
Rust should be the primary guest/source language for Disasmer.
Reasons:
```text
explicit async boundaries map well to suspend/checkpoint
strong types map well to distributed handles
macros can register tasks and environments
source-level debugging is good
one source file can express real build logic
```
C/C++ should be supported later or in parallel as lower-level guest languages, but Rust should define the first-class ergonomic API.
Design rule:
```text
Local things use normal Rust.
Distributed things use Disasmer types.
```
Examples:
```rust
Vec<T> // local
DVec<T> // distributed
std::sync::Mutex<T> // local
disasmer::sync::DMutex<T> // distributed
std::fs // local/WASI-style filesystem, where supported
disasmer::fs // virtual filesystem with flush/sync semantics
```
---
## 17. Rust API shape
The MVP Rust API should be explicit.
Example concepts:
```rust
#[disasmer::main]
async fn main() -> Result<()> { ... }
#[disasmer::task]
async fn compile(target: Target) -> Result<Artifact> { ... }
spawn::task(compile)
.arg(Target::LinuxX64)
.env(env!("linux"))
.start()
.await?;
```
The `env!("linux")` macro validates at build time that an environment resource named `linux` exists.
The `#[disasmer::task]` macro registers a task entrypoint so it can be started remotely by function identity plus serialized arguments.
Task arguments and results should be serializable:
```text
arguments -> serialized into task start message
results -> serialized into join result
handles -> serialized as Disasmer object references
```
---
## 18. Rust example: multiplatform build in one source file
Project layout:
```text
example-build/
src/main.rs
Cargo.toml
Cargo.lock
envs/
linux/Containerfile
windows/Containerfile
macos/flake.nix
macos/flake.lock
inputs/
build-config.json
```
Source file:
```rust
use disasmer::prelude::*;
#[derive(Serialize, Deserialize, Clone, Debug)]
enum Target {
LinuxX64,
WindowsX64,
MacosArm64,
}
impl Target {
fn name(&self) -> &'static str {
match self {
Target::LinuxX64 => "linux-x64",
Target::WindowsX64 => "windows-x64",
Target::MacosArm64 => "macos-arm64",
}
}
fn triple(&self) -> &'static str {
match self {
Target::LinuxX64 => "x86_64-unknown-linux-gnu",
Target::WindowsX64 => "x86_64-pc-windows-msvc",
Target::MacosArm64 => "aarch64-apple-darwin",
}
}
fn output_name(&self) -> &'static str {
match self {
Target::WindowsX64 => "app.exe",
_ => "app",
}
}
}
#[disasmer::main]
async fn main() -> Result<()> {
let completed = DAtomicU32::new(0).await?;
let linux = spawn::task(compile)
.arg(Target::LinuxX64)
.arg(completed.clone())
.env(env!("linux"))
.start()
.await?;
let windows = spawn::task(compile)
.arg(Target::WindowsX64)
.arg(completed.clone())
.env(env!("windows"))
.start()
.await?;
let macos = spawn::task(compile)
.arg(Target::MacosArm64)
.arg(completed.clone())
.env(env!("macos"))
.start()
.await?;
let linux_artifact = linux.join().await?;
let windows_artifact = windows.join().await?;
let macos_artifact = macos.join().await?;
package(vec![linux_artifact, windows_artifact, macos_artifact]).await?;
assert_eq!(completed.load(Ordering::SeqCst).await?, 3);
fs::sync().await?;
Ok(())
}
#[disasmer::task]
async fn compile(target: Target, completed: DAtomicU32) -> Result<Artifact> {
let target_name = target.name();
let triple = target.triple();
let output_name = target.output_name();
cmd!("cargo", "build", "--release", "--target", triple)
.cwd("/vfs/project")
.run()
.await?;
let built_file = format!(
"/vfs/project/target/{triple}/release/{output_name}"
);
let artifact_file = format!(
"/vfs/artifacts/{target_name}/{output_name}"
);
fs::copy(&built_file, &artifact_file).await?;
// Publish this task's filesystem changes so other tasks can see the artifact.
fs::flush().await?;
completed.fetch_add(1, Ordering::SeqCst).await?;
Ok(Artifact::from_path(artifact_file).await?)
}
#[disasmer::task]
async fn package(outputs: Vec<Artifact>) -> Result<()> {
fs::create_dir_all("/vfs/artifacts/dist").await?;
for output in outputs {
fs::copy(output.path(), "/vfs/artifacts/dist/").await?;
}
fs::flush().await?;
Ok(())
}
```
---
## 19. What the Rust example does
The example defines a complete multiplatform build as one Rust program.
It does this:
```text
1. Starts one Disasmer Virtual Process.
2. Creates one distributed atomic counter.
3. Spawns three virtual tasks:
- Linux x64 build task
- Windows x64 build task
- macOS ARM64 build task
4. Places each task into an environment discovered from envs/<name>/.
5. Runs each build command in that environment.
6. Copies each produced binary into /vfs/artifacts.
7. Calls fs::flush() to publish each task's artifact.
8. Joins all tasks.
9. Packages all artifacts into /vfs/artifacts/dist.
10. Calls fs::sync() to make final outputs durable.
```
Runtime behavior:
```text
env!("linux")
-> resolved from envs/linux/Containerfile
env!("windows")
-> resolved from envs/windows/Containerfile
env!("macos")
-> resolved from envs/macos/flake.nix + flake.lock
spawn compile Linux
-> coordinator finds a node capable of running the linux environment
-> node runtime materializes/caches the environment
-> task runs with its own VFS overlay
spawn compile Windows
-> coordinator finds a node capable of running the windows environment
-> task runs separately but in the same virtual process
spawn compile macOS
-> coordinator finds a node capable of running the macos environment
-> task runs separately but in the same virtual process
```
Debugger behavior:
```text
VS Code sees one process:
Thread 1: main
Thread 2: compile LinuxX64
Thread 3: compile WindowsX64
Thread 4: compile MacosArm64
Thread 5: package
```
The user can set breakpoints in:
```text
main()
compile()
package()
```
When a breakpoint hits, Disasmer enters a Debug Epoch and stops the whole virtual process.
---
## 20. What the Rust example proves
The example proves the core Disasmer thesis:
```text
A distributed, multiplatform build can be expressed as normal source code,
run across different machines/environments,
and debugged as one normal multithreaded program.
```
It proves these specific capabilities:
```text
one source file can define the build graph
Containerfiles/Nix flakes can be project resources, not CI YAML
source code can reference environments by logical name
virtual tasks can run on different operating systems/architectures
artifacts can be published through flush()
final outputs can be made durable through sync()
shared distributed state can use explicit Disasmer types
the debugger can show all tasks as threads of one process
```
It also demonstrates the intended mental model:
```text
Build = Virtual Process
Build Step = Virtual Thread / Virtual Task
Containerfile/Nix flake = Environment Resource
Build output = VFS artifact
flush() = publish/synchronization point
sync() = durability point
```
---
## 21. What this makes possible
Disasmer makes these workflows possible:
```text
multiplatform builds without proprietary CI YAML
source-level debugging of build logic
breakpoints inside distributed build orchestration
restart one failed build task after editing source
inspect all build tasks in one debugger session
share artifacts through a versioned virtual filesystem
run Linux/Windows/macOS tasks from one source file
mix Wasm orchestration with containerized native commands
make distributed execution feel like threaded programming
```
Example VS Code loop:
```text
1. Press F5.
2. Build starts as one virtual process.
3. Windows task fails.
4. Breakpoint/trap stops the virtual process.
5. User edits src/main.rs or project source.
6. User runs "Disasmer: Restart Failed Task".
7. Disasmer rebuilds the bundle.
8. Only the failed task restarts if compatible.
9. Breakpoints are rebound.
10. User continues debugging.
```
This is intentionally different from typical CI systems:
```text
not a pile of YAML
not tied to one proprietary platform
not opaque remote job logs only
not separate debuggers per machine
```
---
## 22. C/C++ support
C/C++ should be possible but should not define the primary user experience.
C-style API shape:
```c
dis_task_t linux = dis_spawn_env("linux", compile_task, &args, sizeof(args));
dis_join(linux);
dis_fs_flush();
dis_fs_sync();
```
Distributed memory in C should use handles:
```c
dis_ref_t buffer = dis_mem_alloc(1024);
dis_mem_read(buffer, 0, tmp, sizeof(tmp));
dis_mem_write(buffer, 0, data, len);
```
The MVP should not make raw C pointers transparently remote.
Rust remains the preferred source language because it gives better type safety, async ergonomics, task registration, and IDE UX.
---
## 23. Failure semantics
MVP failure behavior should be simple.
If a node with non-replicated guest state is lost:
```text
the virtual process is considered crashed
```
If a task is checkpointed and its checkpoint data is durable:
```text
the task may be resumed elsewhere
```
If a task has only unflushed local filesystem changes and its node is lost:
```text
those unflushed changes are lost
```
If artifacts have been flushed but not synced:
```text
they may be visible but not durable
```
If artifacts have been synced:
```text
they should survive according to the configured replication policy
```
Do not pretend missing non-replicated state can be debugged.
---
## 24. Security and identity
Disasmer should treat cluster identity and bundle identity as core primitives.
MVP requirements:
```text
nodes authenticate to the coordinator
coordinator authorizes nodes for environments/capabilities
bundles are content-addressed
bundle manifests are signed or integrity-checked
environment resources are resolved by digest
tasks run with explicit capabilities
filesystem access is scoped to the virtual filesystem unless granted
network access is explicit per environment/task
```
The source should not casually select real machines by name. It should select logical environments and capabilities.
---
## 25. MVP feature set
The MVP should include:
```text
Rust SDK
#[disasmer::main]
#[disasmer::task]
env!("name") environment references
auto-discovery of envs/<name>/Containerfile
auto-discovery of envs/<name>/Dockerfile
auto-discovery of envs/<name>/flake.nix
bundle manifest generation
selected input file bundling
per-task VFS overlay
fs::flush()
fs::sync()
spawn task into environment
join task
basic distributed handles
all-stop debugging
Debug Epochs
lazy memory/filesystem snapshotting
VS Code launch/debug extension
restart selected task from clean boundary after rebuild
QUIC node-to-node transport
coordinator-based node discovery
```
MVP restrictions:
```text
all-stop debugging only
cooperative safepoints only
task restart, not live hot-swap
explicit distributed types only
no transparent raw remote pointers
no checkpointing live sockets
no automatic survival of non-replicated node loss
no eager full-cluster memory copy by default
no global consensus on every data operation
```
---
## 26. Later extensions
Possible later extensions:
```text
non-stop debugging
live code replacement for compatible functions
state-schema-aware checkpoint migration
replicated memory spaces
recoverable distributed locks
watchpoints across distributed memory
record/replay debugging
artifact cache sharing across clusters
remote execution marketplace
Kubernetes backend
cloud worker backend
local laptop cluster mode
full offline vendored bundles
language SDKs for C/C++, Go, Zig, Python/Wasm
```
These are not MVP requirements.
---
## 27. Design summary
Disasmer is:
```text
a distributed Wasm runtime
that presents a cluster as one virtual process
with virtual threads/tasks, sharded memory,
per-thread virtual filesystems, checkpoint/suspend/resume,
container/Nix-backed execution environments,
and normal debugger support.
```
For build systems, Disasmer means:
```text
Build = Virtual Process
Build Step = Virtual Thread / Virtual Task
Environment = Containerfile / Dockerfile / Nix flake resource
Artifact = VFS-published file
Debugger = normal VS Code session
```
The core UX promise:
```text
Add a Containerfile or flake.nix to the project.
Reference it from Rust with env!("name").
Press F5.
Debug the distributed build/program like one normal process.
```
The internal truth:
```text
normal debugger illusion
backed by
cluster-wide debug epochs
copy-on-write snapshots
node runtimes
QUIC peer links
distributed memory spaces
filesystem overlays
checkpoint manifests
environment caches
and a consensus-backed control plane
```