Skip to main content
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 current public crates.io releases by default, then the official GitHub repository at a full immutable revision when the needed change is not published. A local checkout is a separate, explicitly requested, nonportable framework-development workflow.

Use when

Use this playbook when a Stoffel app fails to init, check, build, run, test, execute locally, generate bindings, or connect through the SDK/network path.

Goal

Diagnose app-level issues systematically and collect real evidence before reporting success.

First commands

From the app root:
If the app has tests:
If Rust SDK code is involved:
If local MPC is involved:
Label every command with its execution context: app checkout, framework checkout, deployment host, container, or CI. Include the working directory; do not merge output from different contexts into one unlabeled transcript.

Portability and provenance diagnosis

Capture provenance before changing code or dependencies:
  • app repository URL, commit, branch/tag if relevant, and clean/dirty state;
  • framework repository URL, commit, and clean/dirty state if a framework checkout is in use;
  • CLI installation source, resolved executable path, and reported version/build identity when available;
  • SDK source (public package version or git URL and revision, or the exact intentional local path);
  • committed lockfile path and hash, or why no lockfile applies;
  • bytecode hash and generated binding/manifest hashes;
  • immutable build/runtime image digest when containers are involved.
For Rust consumers, inspect the resolved graph rather than trusting the manifest alone:
Inspect all relevant Cargo.toml files for [patch], [replace], path =, git revisions, and workspace-inherited dependencies. Inspect repository and applicable user/global .cargo/config and .cargo/config.toml files for source replacement, registries, aliases, target settings, and injected build flags. Record the resolved SDK package source from cargo metadata and compare it with the lockfile. Do not delete a patch or path dependency until you know whether it was intentional; do not call the result portable while it remains dependent on undeclared local state. Reproduce the failure from a clean external app checkout, outside the framework repository, with only documented public CLI/SDK dependencies and the committed lockfile. The public dependency consumer proof must check/build, produce bytecode and bindings, and exercise the relevant client-facing path without framework workspace inheritance, source mounts, unpublished package caches, or dirty generated files. Framework workspace tests do not substitute for this proof. If that external proof was not run or requires local framework state, classify the result explicitly as not clean-room tested. State why, instead of reporting a portability success.

Container and CI diagnosis

  • Record the image digest, network mode, published ports, working directory, environment overrides, and every host-to-container mount.
  • Inspect mounts for framework checkouts, host target/ directories, local SDK paths, package caches containing unpublished builds, stale generated bindings, and shadowed config/lockfiles.
  • Hash bytecode and bindings both outside and inside the container. Treat a mismatch as bundle mutation or a mount-selection failure.
  • Remember that localhost/127.0.0.1 names the current network namespace. Record bind and advertised addresses separately, then test coordinator, mesh, and RPC reachability from the failing peer/client context.
  • In CI, make clean checkout, public dependency resolution, lockfile stability, artifact hash agreement, image digest capture, config validation, and real service/client smoke separate gates. Fail on unexpected path/patched dependencies or bundle drift.
  • Report every gate as passed, failed, or skipped. Every skip needs the exact reason, execution context, and impact; use not clean-room tested or deployment unverified where appropriate.

Config checklist

Inspect Stoffel.toml:
  • [package] exists.
  • name and version are non-empty.
  • package.name uses only letters, numbers, -, and _.
  • build.source is relative, inside the project, and either a .stfl file or source directory.
  • build.target_dir is a relative directory, not under src/, and not a file path.
  • optimization_level is 0..3 if present.
  • [mpc].parties, [mpc].threshold, and [mpc].instance_id are unquoted positive whole numbers where present.
  • Byzantine validation holds: HoneyBadger needs at least 4 * threshold + 1 parties.
  • Backend syntax is valid: honeybadger, avss, avss:bls12_381, avss:bn254, avss:curve25519, avss:ed25519, avss:secp256k1, avss:p-256.
  • curve/field is only used where a backend/curve combination supports it.

Input checklist

  • Named function inputs use repeated --input NAME=VALUE.
  • ClientStore inputs use repeated --client-input SLOT=VALUE.
  • Repeating the same ClientStore slot appends values in order for ClientStore.take_share(slot, index).
  • Do not combine multiple assignments in one flag.
  • Named input names must match function parameters exactly.
  • Client slots must be numeric.
  • If using input files, extensions must be .json, .csv, or .txt.
  • Named JSON inputs are an object like {"a": 40, "b": 2}.
  • Client JSON inputs are an object keyed by numeric slot like {"0": [40, 2]}.
  • Client CSV inputs require slot,value or client_slot,value headers.
  • TXT input files use one name=value or slot=value assignment per line; blank lines and # comments are ignored.
  • CLI values are integers, booleans, strings/JSON where accepted by file parsing, or 0x-prefixed bytes where supported.

Bytecode checklist

  • Rebuild .stflb after source changes.
  • Regenerate typed bindings after bytecode changes.
  • Explicit SDK backend/curve must match bytecode metadata. Prefer generated ProgramManifest for ClientStore apps.
  • Use --program-info or disassembly when diagnosing wrong entrypoint/function/client metadata.
  • If a source directory is configured, confirm the intended file was compiled; the CLI can compile multiple .stfl files.

Local MPC checklist

  • Increase --timeout-secs before declaring protocol failure.
  • Avoid concurrent local party meshes that collide on ports/processes.
  • Verify whether the app uses named inputs or ClientStore inputs.
  • For examples with a first-line # run-args: header, copy those exact flags.
  • Include --expected-output-clients N for programs that call MpcOutput.send_to_client or Share.send_to_client.

Typed bindings checklist

  • Bindings were generated from the same .stflb loaded at runtime.
  • Rust code includes generated bindings after generation.
  • cargo check was run after regeneration.
  • If duplicate crate/output collision errors appear with path or git dependencies, pre-generate bindings or remove the duplicate SDK build-dependency.

Network/off-chain checklist

  • Local smoke passes before network work.
  • Network config is not project Stoffel.toml.
  • Client slot exists in program metadata.
  • Generated bindings came from the same .stflb.
  • Coordinator address, node RPC addresses, timestamp, identity material, and expected certificates are provided.
  • Network config validates server addresses, expected parties, expected clients, threshold, backend, and preprocessing.
  • Bytecode hash, generated binding version, party configs, coordinator settings, node RPC addresses, and identity material are from the same deployment bundle.
  • If live server startup is delegated to lower-layer tooling, capture the exact service command/supervisor logs instead of reporting SDK builder success as deployment success.

Minimal diagnosis report

When handing off a failure, include:
  • command run
  • working directory
  • stoffel --help/version if relevant
  • app Stoffel.toml with secrets removed
  • exact error output
  • whether stoffel status --verbose passed
  • whether stoffel check passed
  • whether bytecode was rebuilt
  • whether typed bindings were regenerated
  • exact # run-args: header if using an example
  • network/off-chain config shape with secrets redacted if relevant
  • bytecode hash and generated binding timestamp/hash for deployment failures
  • labeled execution context and exact working directory
  • app/framework repository URL, commit, and clean/dirty state
  • CLI source/path, SDK source, lockfile path/hash, and applicable image digest
  • relevant cargo metadata package source plus any [patch], .cargo source replacement, local path, or workspace inheritance found
  • container mount map and bind/advertised addresses when applicable
  • exit status, first actionable error, and location of complete unabridged output
  • each check that passed, failed, or was skipped; include the reason and impact of every skip
  • clean external consumer proof result, or the explicit classification not clean-room tested

Common pitfalls

  • Do not “fix” app issues by editing framework internals unless the task is explicitly a framework bug report.
  • Do not report success from a command that was not run.
  • Do not leak private client inputs, tokens, identity material, or secrets into notes, logs, Obsidian, HackMD, or public issues.
  • Do not store API tokens in Stoffel.toml, app repos, Obsidian, or HackMD.
  • Do not call deployment done from execute_local() output or SDK builder construction alone.
  • Do not mistake a host framework mount, package cache, [patch], .cargo source replacement, or path dependency for public dependency portability.
  • Do not summarize a partial run as success: preserve the exact failure and list checks that never ran.