Declaration cookbook
Use declarations when you want code-first workload authoring without executing the user module during compile. The static compiler reads the supported literal shape and emits Workload IR for the same build and launch path used by the CLI.
This page uses the current Python and TypeScript declaration helpers. It avoids
runtime-only Sandbox.create(...) calls; use Operations cookbook
for imperative sandbox lifecycle scripts.
Minimal function
Section titled “Minimal function”import mvm
mvm.workload(id="hello-python")
@mvm.app( name="hello", source=mvm.local_path(".", include=["src/**", "pyproject.toml", "uv.lock"]), image=mvm.python_image(python="3.12", packages=["uv"]), resources=mvm.resources(cpu_cores=1, memory_mb=512, rootfs_size_mb=1024), dependencies=mvm.python_deps(lockfile="uv.lock", tool="uv"), network=mvm.network(mode="none"), entrypoint=mvm.entrypoint_function( module="src.tool", function="run", primary=True, ),)def run(prompt: str) -> str: return prompt.upper()Compile and build:
mvmctl compile ./tool.py --out /tmp/hello-pythonmvmctl build /tmp/hello-pythonSecurity posture:
mode="none"is the default closed network posture;- the lockfile is declared so dependency integrity can be checked;
- source includes are narrow rather than copying the entire home directory;
- the function body is guest workload code and is not executed during static declaration extraction.
import * as mvm from "mvm-sdk";
mvm.workload({ id: "hello-node" });
export const run = mvm.app({ name: "hello", source: mvm.localPath(".", { include: ["src/**", "package.json", "pnpm-lock.yaml"] }), image: mvm.node_image({ node: "22", packages: ["pnpm"] }), resources: mvm.resources({ cpu_cores: 1, memory_mb: 512, rootfs_size_mb: 1024 }), network: mvm.network({ mode: "none" }), entrypoint: mvm.entrypoint_function({ module: "src/tool", function: "run", primary: true, }),})((prompt: string): string => prompt.toUpperCase());Compile and build:
mvmctl compile ./tool.ts --out /tmp/hello-nodemvmctl build /tmp/hello-nodeCommand entrypoint
Section titled “Command entrypoint”Use a command entrypoint when the workload should boot into a process instead of exposing a function-call entrypoint.
@mvm.app( name="worker", source=mvm.local_path(".", include=["worker.py", "uv.lock"]), image=mvm.python_image(packages=["uv"]), resources=mvm.resources(cpu_cores=1, memory_mb=512, rootfs_size_mb=1024), dependencies=mvm.python_deps(lockfile="uv.lock"), network=mvm.network(mode="none"), entrypoint=mvm.entrypoint(command=["python", "/app/worker.py"]),)def worker() -> None: passexport const worker = mvm.app({ name: "worker", source: mvm.localPath(".", { include: ["worker.ts", "pnpm-lock.yaml"] }), image: mvm.nodeImage({ packages: ["pnpm"] }), resources: mvm.resources({ cpu_cores: 1, memory_mb: 512, rootfs_size_mb: 1024 }), dependencies: mvm.nodeDeps({ lockfile: "pnpm-lock.yaml" }), network: mvm.network({ mode: "none" }), entrypoint: mvm.entrypoint({ command: ["node", "/app/worker.js"] }),})(() => undefined);Keep startup commands deterministic. Fetching unpinned code in an entrypoint or hook weakens the audit story because the build artifact no longer captures the full workload input.
Explicit egress
Section titled “Explicit egress”Use closed networking by default. When a workload needs outbound access, make the destination concrete.
network=mvm.network( mode="bridge", egress=mvm.egress([ mvm.host_port("api.openai.com", 443), ]), dns=mvm.dns_system(),)network: mvm.network({ mode: "bridge", egress: mvm.egress([ mvm.hostPort("api.openai.com", 443), ]), dns: mvm.dnsSystem(),})Security posture:
- allow specific hosts and ports, not broad wildcard listeners;
- keep DNS behavior explicit for workloads that depend on names;
- review generated IR before moving a workload from
mode="none"tomode="bridge".
Secret references
Section titled “Secret references”Declarations should refer to secrets without embedding raw values in source.
env={ "MODEL": mvm.literal("gpt-4.1-mini"), "OPENAI_API_KEY": mvm.secret("openai-api-key", var="OPENAI_API_KEY"),}env: { MODEL: mvm.literal("gpt-4.1-mini"), OPENAI_API_KEY: mvm.secret("openai-api-key", { var: "OPENAI_API_KEY" }),}The SDK declaration records the reference. Secret resolution belongs to the runtime admission path, and logs/errors should not print resolved values.
Hooks are useful for deterministic setup that belongs in the workload contract.
@mvm.app( name="service", source=mvm.local_path("."), image=mvm.python_image(packages=["uv"]), resources=mvm.resources(cpu_cores=1, memory_mb=512, rootfs_size_mb=1024), network=mvm.network(mode="none"), entrypoint=mvm.entrypoint(command=["python", "/app/server.py"]), before_build=mvm.hook(["uv", "sync", "--frozen"]), before_start=mvm.hook("python /app/migrate.py"), after_start=mvm.hook(["python", "/app/healthcheck.py"]),)def service() -> None: passexport const service = mvm.app({ name: "service", source: mvm.localPath("."), image: mvm.nodeImage({ packages: ["pnpm"] }), resources: mvm.resources({ cpu_cores: 1, memory_mb: 512, rootfs_size_mb: 1024 }), network: mvm.network({ mode: "none" }), entrypoint: mvm.entrypoint({ command: ["node", "/app/server.js"] }), beforeBuild: mvm.hook(["pnpm", "install", "--frozen-lockfile"]), beforeStart: mvm.hook(["node", "/app/migrate.js"]), afterStart: mvm.hook(["node", "/app/healthcheck.js"]),})(() => undefined);Security posture:
- prefer argv hooks for commands with user-controlled values;
- keep hooks deterministic and tied to pinned inputs;
- avoid network-fetching hooks unless policy and provenance explicitly allow them.
Multiple entrypoints
Section titled “Multiple entrypoints”One declaration can expose multiple function entrypoints. Mark the default with
primary=True.
@mvm.app( name="math", source=mvm.local_path(".", include=["mathsvc.py"]), image=mvm.python_image(), resources=mvm.resources(cpu_cores=1, memory_mb=256, rootfs_size_mb=512), network=mvm.network(mode="none"), dependencies=mvm.no_deps(), entrypoints=[ mvm.entrypoint_function(module="mathsvc", function="add", primary=True), mvm.entrypoint_function(module="mathsvc", function="mul"), ],)def math() -> None: passexport const math = mvm.app({ name: "math", source: mvm.localPath(".", { include: ["mathsvc.ts"] }), image: mvm.nodeImage(), resources: mvm.resources({ cpu_cores: 1, memory_mb: 256, rootfs_size_mb: 512 }), network: mvm.network({ mode: "none" }), dependencies: mvm.noDeps(), entrypoints: [ mvm.entrypointFunction({ module: "mathsvc", function: "add", primary: true }), mvm.entrypointFunction({ module: "mathsvc", function: "mul" }), ],})(() => undefined);Use separate apps when the entrypoints need different resource, network, or secret policy.
Review before build
Section titled “Review before build”Before a declaration becomes a shared artifact:
- compile to a temporary output path;
- inspect the generated Workload IR and source bundle;
- confirm source include/exclude rules are narrow;
- confirm network starts closed and grants are concrete;
- confirm dependency lockfiles are present and pinned;
- confirm secrets are references;
- confirm hooks do not fetch unpinned code;
- build through the normal secure build boundary.