Skip to main content

Stoffel Local MPC Dev Loop

Scope: AI-agent-agnostic playbook for building applications with the Stoffel framework. This is not a maintainer guide for compiler, VM, protocol, or release engineering work. Dependency assumption: use the public 0.1.0 install snippets from these docs. When developing against a local checkout, make that source-based workflow explicit.

Use when

Use this playbook when an app needs local MPC smoke testing, ClientStore input runs, hot reload, or SDK local coordinator-backed execution.

Goal

Give developers a repeatable local loop for testing private/MPC apps before any real network deployment.

Current source of truth

  • crates/stoffel-cli/src/main.rs
  • crates/stoffel-rust-sdk/README.md
  • crates/stoffel-rust-sdk/src/runtime.rs
  • crates/stoffel-lang/examples/README.md
  • crates/stoffel-lang/examples/**/*.stfl

Runner setup

For source-based local development, build the runner from a local checkout:
cd /path/to/stoffel
cargo build -p stoffel-vm --bin stoffel-run
The CLI and SDK can find the runner through:
  • stoffel run --runner /path/to/stoffel-run
  • stoffel dev --runner /path/to/stoffel-run
  • STOFFEL_RUN_BIN=/path/to/stoffel-run
  • SDK .local_runner_path("/path/to/stoffel-run")
  • SDK runtime.local_network().runner_path("/path/to/stoffel-run")
Build the runner inside the same environment where it will be executed.

CLI local run

stoffel run --timeout-secs 180
stoffel run path/to/main.stfl --runner target/debug/stoffel-run --timeout-secs 180
stoffel run target/debug/app.stflb --program-info --timeout-secs 180
Local mode is the default unless --network or --config is set.

Hot reload

stoffel dev --once --timeout-secs 180
stoffel dev --poll-ms 500 --timeout-secs 180
Use --once for CI/smoke checks and default watch mode during interactive development.

Input paths

Named function args:
stoffel run --input a=40 --input b=2
.with_inputs(&[("a", 40_i64), ("b", 2_i64)])
ClientStore values:
stoffel run --client-input 0=40 --client-input 0=2 --expected-output-clients 1
.with_client_input(0, &[40_i64, 2_i64])
.expected_output_clients(1)
The CLI also supports --input-file and --client-input-file for .json, .csv, and .txt inputs. See Stoffel CLI App Workflow.

Use example run-args headers

Many secret examples include the exact local flags in the first source line:
# run-args: --client-input 0=50 --client-input 0=20 --client-input 0=40 --client-input 0=10 --client-input 0=30 --expected-output-clients 1
Run by appending those flags:
stoffel run crates/stoffel-lang/examples/mpc_top_k/main.stfl \
  --client-input 0=50 --client-input 0=20 --client-input 0=40 \
  --client-input 0=10 --client-input 0=30 \
  --expected-output-clients 1 \
  --timeout-secs 180
For repeated client slots, order matters: --client-input 0=50 --client-input 0=20 maps to ClientStore.take_share(0, 0) then ClientStore.take_share(0, 1).

SDK local run

let result = runtime
    .local_network()
    .entry("main")
    .runner_path("target/debug/stoffel-run")
    .timeout(std::time::Duration::from_secs(180))
    .run()
    .await?;
Builder shortcut:
let result = Stoffel::compile_file("src/main.stfl")?
    .parties(5)
    .threshold(1)
    .with_client_input(0, &[42_i64])
    .expected_output_clients(1)
    .execute_local()
    .await?;
  1. Run stoffel status --verbose from the app root.
  2. Run stoffel check to catch syntax/config/type errors.
  3. Run stoffel build --program-info to inspect bytecode and client IO metadata.
  4. Run stoffel run --timeout-secs 180 with named inputs or documented # run-args: flags.
  5. If using Rust, run cargo check and cargo run against the same bytecode/source.
  6. Only then move to network/off-chain config.

Validation / done criteria

For app local-MPC work:
stoffel status --verbose
stoffel check
stoffel build --program-info
stoffel run --timeout-secs 180 <inputs or documented run-args>
For 0.1.0 framework example validation:
cd /path/to/stoffel/crates/stoffel-lang
./examples/validate_examples.sh
STOFFEL_PROGRAM_NAME=mpc_runtime_info.stflb ./examples/validate_examples.sh --host-mpc

Common pitfalls

  • Compile-only success is not a local MPC smoke test.
  • Increase --timeout-secs before assuming protocol failure.
  • Avoid port/process collisions by serializing tests that spawn local party meshes.
  • Keep ClientStore inputs separate from named function inputs.
  • Do not omit --expected-output-clients for examples/programs that send client outputs.
  • AVSS support is backend/curve/input dependent; verify the current SDK boundary.