Mélodium 0.11: secrets in the language, tracks in parallel
Mélodium 0.11 is out. It changes the language: credentials now have a type of their own. The engine and its packages also get faster, more robust, and more secure. Some of these changes break existing programs, so the end of this post lists what to update.
Secrets as a type
API keys, passwords, and tokens used to travel through programs as plain string parameters, which meant they could end up in logs, debug files, execution reports, or the arguments of a process. Mélodium 0.11 adds Secret<T>, most often used as Secret<string>.
A secret holds where its value comes from, not the value itself. On the command line and in defaults, a secret parameter takes a locator:
treatment main(const db_password: Secret<string> = "env:MELODIUM_SECRET_DB_PASSWORD")melodium run Compo.toml --db_password file:/run/secrets/db_passwordThree sources exist: env: for environment variables, file: for files, and vault: for HashiCorp Vault and OpenBao through the new vault package. Programs only see the environment variables prefixed with MELODIUM_SECRET_, so the variables configuring Mélodium itself stay out of their reach. --check-secrets resolves every secret before the run starts, so a missing variable fails right away instead of halfway through.
Only the elements that need a value reveal it, at the moment they use it. SqlPool reads its password when connecting, HttpClient adds its secret headers to each request, process environments give secrets to commands as variables or on their standard input (never in their arguments), and the remote LLM, speech, and HuggingFace providers of ml take their keys as secrets. Every reveal is recorded as a debug event, and revealed values are masked as <secret "name"> in log messages. Plaintext is overwritten once it is no longer needed, and before the process exits.
Each secret also carries a policy: which elements may reveal it, whether it may ever become ordinary data, and whether it may leave the engine when the program is distributed (never by default, by locator only, or by value over TLS only). The Secrets page of the documentation covers all of it.
Checking what you receive: the crypto package
Secrets are not only sent; some are received. Incoming HTTP requests now give their Authorization and Cookie headers only as secrets, and a server can declare other headers the same way, such as the token of GitLab webhooks.
The new crypto package checks those values without revealing them to the program. It verifies HMAC signatures (SHA-256, SHA-384, SHA-512, SHA-1) and Ed25519 signatures, compares tokens in constant time, signs and verifies JSON Web Tokens, and generates random tokens as secrets.
A new tutorial step shows it at work: Signed Webhooks receives webhooks from GitHub and GitLab, verifies the GitHub HMAC signature and the GitLab token, and only answers 200 once the request is proven genuine. The existing examples were updated too: the LLM showcases, the SQL tutorial, and the distributed computation tutorial all take their credentials as secrets now.
Moving to smol
Mélodium now runs on smol , replacing async-std, which was discontinued. The engine owns its runtime: tracks and the continuous tasks of models run on threads it manages, and Unix signals are received through async-signal. The whole standard library moved along: the HTTP server and client run on trillium-smol, SQL on sqlx 0.9 with its smol runtime, files and processes on async-fs and async-process, and the remote providers of ml and the Kubernetes calls of work run in a Tokio context given by async-compat.
With the engine in charge of its threads, tracks now run in parallel, on one thread per core by default. Programs handling many independent tracks, such as an HTTP server answering concurrent requests, use every core without any change to their code. The MELODIUM_THREADS environment variable sets another number of threads.
Ending a run cleanly
On Linux and macOS, SIGINT, SIGTERM, and SIGHUP now ask the run to end: running tracks get 10 seconds to finish, and a second signal stops them right away, along with the commands they started. Mélodium exits with code 128 plus the signal number. On Windows, Ctrl+C, Ctrl+Break, closing the console, logging off, and shutting down are handled as a best effort, exiting with STATUS_CONTROL_C_EXIT. A program that cannot be launched now exits with code 1.
Stricter distribution
melodium dist takes its authentication keys from files (--recv-key-file, --send-key-file) or from the MELODIUM_DIST_RECV_KEY and MELODIUM_DIST_SEND_KEY environment variables. --recv-key and --send-key still work, with a warning, since other local users can read process arguments. Plain TCP (--disable-tls) is now refused on addresses other than loopback ones unless --allow-plain-tcp is given.
The distribution certificates were renewed under a new root, “Mélodium Distribution Root G2”, valid until 2036. The previous root expires at the end of December 2026 and is no longer trusted: every engine taking part in a distributed run must be on 0.11.
Choosing where workers run
work/distant gets a system parameter to request an operating system, a Linux distribution, or an exact machine image for a worker. Architectures cover every one of the OCI image specification, Rust’s own names (x86_64, aarch64…) are accepted as aliases, and |local_arch gives the architecture of the machine running the engine. The cicd package follows: setupRunner takes the same system parameter, and its GitHub and GitLab status tokens are secrets, read by default from MELODIUM_SECRET_GITHUB_TOKEN and MELODIUM_SECRET_GITLAB_TOKEN.
What to update
- Credentials: the
api_keyofRemoteLlm,RemoteStt, andRemoteTts, thetokenofHfHub, and the keys of|new_accessare now secrets. Declare the matching parameters asSecret<string>, give them with|wrap<Secret<string>>(...), and pass locators instead of values, such asenv:MELODIUM_SECRET_ANTHROPIC_API_KEY. The updated showcases show the pattern. - HTTP servers:
AuthorizationandCookieare no longer in the request headers, only in the secrets of@HttpRequest. - Architectures:
simpleStepand its variants no longer default toarm64whenarchis none; the container runs on the architecture of its worker.|containerand|service_containertake an optional architecture, written|wrap<Arch>(...). Compose refuses architectures different from the host one. - Editions:
distantsends no edition when the program gives none, meaning any edition suits, instead ofscratch. - Function calls: calls with more parameters or generics than the function takes are now refused; they used to be silently ignored.
- Rust: building Mélodium requires Rust 1.94, and library users will find breaking changes in the engine API (smol tasks, secret access in treatments and models).
Full details for every crate are in the CHANGELOG . As usual, upgrade with cargo install melodium or grab a prebuilt binary.
