npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lufs-audio/workchain

v0.1.0

Published

Agent-first CLI for LUFS Workchain: compose verified audio processing steps into YAML chains

Downloads

120

Readme

Workchain

A YAML-driven, agent-first audio processing engine where "it worked" means proven, not exited 0.

# chains/deliverable-voice.yaml — prep a recording to a dialogue delivery spec
name: "Deliverable: Voice / Dialogue"
version: "1.0"
steps:
  - name: format_conversion
    params:
      target_format: wav
      sample_rate: 48000
      bit_depth: 24
      channels: 1
  - name: normalization
    params:
      target_lufs: -21
      true_peak: -3.0
  - name: audio_benchmark
    params:
      expected_spec: "24/48000/1"
workchain run deliverable-voice take-07.wav -o ./out

If the conversion does not actually come out at 48 kHz / 24-bit / mono, that step fails. If the normalizer misses −21 LUFS, that step fails. Not "warns" — fails, with the measured value, and the chain stops. The component does not get to grade its own homework.

Real output from the second case, on a signal whose crest factor makes the target unreachable under the peak ceiling:

✗ normalization — verification FAILED (1 of 8 checks)
    integrated_loudness_on_target: measured -10.56 LUFS vs target -5.0 (±1.0) → off by 5.56 LU
Chain halted: step 'normalization' failed

The component exited 0 and reported "Normalization completed". The verifier disagreed.


The problem this exists for

Audio DSP almost never crashes. It produces something: silence, a 6 dB level error, a 30 ms truncation, a decorrelated stereo image, two seconds of −64 dBFS. Every one of those is a valid audio file that passes every check a normal pipeline makes.

That was survivable while a human sat in the loop, because the ear is a post-condition — it fires automatically and it cannot be fooled by a byte count. Automation deletes that sensor and, by default, replaces it with nothing. An agent cannot listen. It reads an exit code, and an exit code cannot tell the difference between a stretched sound and an empty file.

So a component that runs but produces the wrong output is worse than one that fails, because it lies to whatever is operating it. A tool that fails is a nuisance. A tool that lies is a liability, because it spends trust it did not earn and the bill arrives later, for someone who has stopped checking.

Workchain's answer is that every component declares a contract, and a single verifier enforces it after every run.

How it works

A component is a folder. That is the whole registry — there is no database.

components/normalization/
├── step.yaml      # params, outputs, requirements (verified IN), verify (verified OUT)
├── run.sh         # does the work
└── README.md

Its step.yaml declares two contracts:

Verified IN — checked before run.sh executes. Missing ffmpeg, missing model, wrong Python version: the step fails immediately with a clear message, instead of half-running and dying somewhere in the middle.

requirements:
  commands: [ffmpeg, ffprobe]

Verified OUT — checked after a clean exit, by lib/workchain_verify.py:

verify:
  outputs:
    - name: primary_output
      assert: [exists, non_empty, audio_valid]
  post_conditions:
    - id: integrated_loudness_on_target
      check: audio_lufs_within
      output: primary_output
      target_param: target_lufs
      tolerance: 1.0

audio_valid re-measures the file with ffprobe and requires a positive duration. audio_lufs_within independently re-measures the loudness and compares it to what was asked for. The component's own logged value is not evidence.

That distinction is the entire design. non_empty asks a filesystem question — a 44-byte WAV header with zero samples in it passes. audio_valid asks an audio question, and it does not. Most silent-failure bugs live in exactly that gap.

Creative operations, where there is no right answer

You cannot assert the correct output of a granular texture. So don't — assert relations instead:

  • duration preserved, or related to the requested factor
  • loudness preserved where the operation should not have changed it
  • separated stems recombine to the source within a residual tolerance
  • the same input and parameters render byte-identically

One trap worth knowing, because we shipped it: an equality assertion between two absent values passes. None == None is true, and CI reported green on a run where the component never started. Equality fails open; inequality fails closed. Guard both sides' existence before comparing.

Three interfaces, one parser

engine/       Bash        ./engine/workchain-engine.sh -c chain.yaml in.wav -o out/
cli/          Node        workchain run <chain> <input> --json
mcp-server/   Python      list_components · get_step_schema · validate_chain · run_chain

All three parse and resolve through lib/workchain_yaml.py. There is no fourth parser, and adding one is the architectural mistake this layout exists to prevent — three interfaces that disagree about what a chain means are three different products.

Built for agents, on purpose

--json on everything. NDJSON progress on stderr, final JSON on stdout. Schema-validated params with declared types and ranges. Meaningful exit codes. --dry-run. validate --strict before you run. Machine-readable discovery in llms.txt and agent.json.

And the part that matters more than any of it: when an agent reports that a step succeeded, that claim has been independently checked.

Quick start

git clone https://github.com/lufs-audio/workchain
cd workchain/cli && npm install && npm link
cd ..

workchain components                     # what's installed
workchain doctor                         # can this machine run them?
workchain chains                         # available chains
workchain run deliverable-voice in.wav -o ./out --json

Requires Node 18+, Python 3.10+, and ffmpeg. The light components need nothing else — no venv, no model weights, no native toolchain.

Write your own:

workchain generate component --name my_thing --description "..."

The scaffold fails until you implement it — the sentinel is in the file, not in a comment — so a generated component can never be mistaken for a working one.

Where to look first

If you only read three files, read these in order:

  1. lib/workchain_verify.py — the whole idea, in one file.
  2. components/normalization/step.yaml — a real contract, including the post-condition that closes the "measured it and never compared it" bug we shipped in this very component.
  3. docs/format.md — the chain and step.yaml specification.

Licensing

Apache-2.0. The format is unencumbered and we want other implementations of it. What is published, what is not, and why: LICENSING.md.

Pull requests are not being accepted yet, for ownership reasons explained plainly in CONTRIBUTING.md. Bug reports — especially "it said it worked and it didn't" — are wanted.

Lineage

Workchain descends from a tradition it did not invent. The Composers Desktop Project (Trevor Wishart, Richard Dobson, Martin Atkins, Archer Endrich, Richard Orton and others, from 1983) established that serious sound transformation could be a set of small composable command-line programs a composer drives directly. That is the shape of this engine, forty years later, with the operator changed and a contract added.

Built by LUFS Audio.