Skip to content

Rust SDK

The Rust SDK at crates/mvmforge-sdk/ is the build-time counterpart to the Python and TypeScript SDKs (see ADR-0015).

It uses an explicit builder pattern rather than decorators — no globals, no implicit registration — and produces canonical IR byte-identical to the Python and TS SDKs for the same logical workload, gated by the cross-SDK corpus (ADR-0003 §7).

Install

The SDK ships as a workspace crate inside this repo. From a Rust project that depends on mvmforge:

[dependencies]
mvmforge-sdk = { path = "path/to/mvmforge/crates/mvmforge-sdk" }

A published crates.io release is part of ADR-0015 Phase 2; until then, use a path or git dependency.

Authoring

use mvmforge_sdk::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let wl = workload("hello")
.app(
app("hello")
.source(local_path("."))
.image(nix_packages(["python312"]))
.entrypoint(entrypoint_command(["python", "-m", "hello"]))
.resources(resources(1, 256, 512))
.build()?,
)
.build()?;
emit(&wl)?;
Ok(())
}

The builders enforce required-field presence at .build() time so the rest of the SDK can take typed values. Errors surface as BuildError and EmitError.

Function entrypoints

let ep = entrypoint_function(
/* module */ "math",
/* function */ "add",
)
.language("python") // defaults to "rust"; cross-language manifest authoring
.format(Format::Json)
.args_schema(args) // optional JSON Schema
.return_schema(ret) // optional JSON Schema
.build()?;

Constructor helpers

Mirroring the Python and TypeScript surfaces:

ConceptHelpers
Sourceslocal_path, nix_derivation, oci_image
Imagesnix_packages, oci_base
Entrypointsentrypoint_command, entrypoint_function
Resourcesresources(cpu_cores, memory_mb, rootfs_size_mb)
Networknetwork, egress, host_port, dns_none/system/resolver
Dependenciespython_deps[_with], node_deps[_with], no_deps

Two-layer architecture

Per ADR-0003:

  • Lower layer — IR types re-exported as-is from mvmforge-ir. No codegen needed; the Rust IR types are already serde + JsonSchema + deny_unknown_fields, which satisfies the schema-driven contract that Python and TypeScript SDKs achieve via datamodel-code-generator / json-schema-to-typescript.
  • Upper layer — hand-authored builders rooted at workload and app.

Imports under mvmforge_sdk::Ir* re-export the IR types under Ir-prefixed aliases for callers who want to deal with raw types directly.

Subprocess contract

Per ADR-0002: emit(&workload) honors MVMFORGE_IR_OUT. When set, writes the canonical IR to that path and returns Ok(()). When unset, writes to stdout. Validation errors and write errors return non-zero through EmitError.

emit_json(&workload) is the in-process variant — returns the canonical IR as a String for callers that want to post-process before writing.

CLI dispatch

mvmforge emit <entry> recognizes Rust entries via two paths:

  • A .rs file with a main() — emits via cargo run against the containing project.
  • A Cargo.toml directory — emits via cargo run --manifest-path <Cargo.toml> against the project’s default binary.

Per-language dispatch lives in crates/mvmforge/src/sdk_dispatch.rs. Adding a new SDK is a new dispatch arm + a new corpus runner.

Out of scope (v1)

ADR-0015 carves these out for future ADRs / plans:

  • Function-entrypoint Rust language support (a workload whose entrypoint is a Rust function dispatched in-VM by a hardened wrapper at nix/wrappers/rust.rs). Build-time DSL only in v1.
  • Runtime SDK (Session, RemoteFunction).
  • Procedural-macro sugar over the builder API.

See also