> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stoffelmpc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Stoffel Local MPC Dev Loop

> Run local MPC smoke tests, ClientStore input flows, hot reload, and SDK local coordinator-backed execution.

> 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: app dependencies come from current public crates.io releases by default. Use a full pinned revision of the official GitHub repository only as fallback; reserve local paths for explicit nonportable framework development.

## 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. Local MPC is a verification gate, not the production topology.

## 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`

## CLI local run

```sh theme={null}
stoffel run --timeout-secs 180
stoffel run path/to/main.stfl --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

```sh theme={null}
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:

```sh theme={null}
stoffel run --input a=40 --input b=2
```

```rust theme={null}
.with_inputs(&[("a", 40_i64), ("b", 2_i64)])
```

ClientStore values:

```sh theme={null}
stoffel run --client-input 0=40 --client-input 0=2 --expected-output-clients 1
```

```rust theme={null}
.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](/developer-skills/stoffel-cli-app-workflow).

## Use example `run-args` headers

Many secret examples include the exact local flags in the first source line:

```stfl theme={null}
# 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:

```sh theme={null}
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

For a Rust app, use the version from the current SDK installation docs and commit `Cargo.lock`:

```toml theme={null}
[dependencies]
stoffel = { package = "stoffel-rust-sdk", version = "<current-docs-version>" }
```

If a needed change is not released, use `git = "https://github.com/Stoffel-Labs/stoffel.git"` with `rev = "<full-40-character-commit-sha>"`. Do not substitute `branch = "main"`. A `path = "../stoffel/crates/stoffel-rust-sdk"` dependency is nonportable and is valid only when deliberately testing framework source.

```rust theme={null}
let result = runtime
    .local_network()
    .entry("main")
    .timeout(std::time::Duration::from_secs(180))
    .run()
    .await?;
```

Builder shortcut:

```rust theme={null}
let source = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
    .join("src/main.stfl");
let result = Stoffel::compile_file(source)?
    .parties(5)
    .threshold(1)
    .with_client_input(0, &[42_i64])
    .expected_output_clients(1)
    .execute_local()
    .await?;
```

## Recommended local loop

1. Resolve the app root from an explicit argument, manifest, or the script's own location; do not assume the caller's CWD.
2. Run `stoffel status --verbose "$APP_ROOT"`.
3. Run `stoffel check "$APP_ROOT"` to catch syntax/config/type errors.
4. Run `stoffel build "$APP_ROOT" --program-info` to inspect bytecode and client IO metadata.
5. Run `stoffel run "$APP_ROOT" --timeout-secs 180` with named inputs or documented `# run-args:` flags.
6. If using Rust, run `cargo check --locked` and `cargo run --locked` with an explicit `--manifest-path` against the same bytecode/source.
7. Inspect `cargo metadata --locked` and prove the app in a clean external checkout.
8. Record the exact command/output in the app handoff.
9. Only then move to network/off-chain config with [Stoffel Deployment Runbook](/developer-skills/stoffel-deployment-runbook).

For a repository script, derive a stable root from the script path:

```sh theme={null}
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
APP_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel)"
APP_MANIFEST="$APP_ROOT/Cargo.toml"
STOFFEL_ROOT="$APP_ROOT"
if [ ! -f "$STOFFEL_ROOT/Stoffel.toml" ] && [ -f "$APP_ROOT/stoffel/Stoffel.toml" ]; then
  STOFFEL_ROOT="$APP_ROOT/stoffel"
fi
test -f "$STOFFEL_ROOT/Stoffel.toml"

stoffel check "$STOFFEL_ROOT"
cargo check --locked --manifest-path "$APP_MANIFEST"
cargo metadata --locked --format-version 1 --manifest-path "$APP_MANIFEST" \
  > "$APP_ROOT/cargo-metadata.json"
```

The Stoffel package in metadata must have a `registry+...` source or a pinned official `git+...#<full-sha>` source. `source: null` exposes a local path/workspace dependency.

## Validation / done criteria

For app local-MPC work:

```sh theme={null}
stoffel status --verbose "$STOFFEL_ROOT"
stoffel check "$STOFFEL_ROOT"
stoffel build "$STOFFEL_ROOT" --program-info
stoffel run "$STOFFEL_ROOT" --timeout-secs 180 <inputs or documented run-args>
cargo check --locked --manifest-path "$APP_ROOT/Cargo.toml"
```

Commit `Cargo.lock`, then clone the app into a temporary directory outside the framework checkout (with no sibling `../stoffel`) and rerun the locked check and local smoke. A pass inside the framework repository alone is insufficient portability proof.

For framework example validation:

```sh theme={null}
FRAMEWORK_ROOT="/absolute/path/to/stoffel"
"$FRAMEWORK_ROOT/crates/stoffel-lang/examples/validate_examples.sh"
STOFFEL_PROGRAM_NAME=mpc_runtime_info.stflb \
  "$FRAMEWORK_ROOT/crates/stoffel-lang/examples/validate_examples.sh" --host-mpc
```

## Common pitfalls

* Compile-only success is not a local MPC smoke test.
* A local MPC pass backed by an adjacent path dependency is not a portable app proof.
* Do not let `cargo run` update the graph implicitly; commit the lockfile and use `--locked`.
* Do not encode framework checkout locations or assume commands start at the repository root.
* Local MPC success is not production deployment; it only proves the program and app boundary work on the local test network.
* 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.
