Adopting noodlelab in an existing project

These are the steps for an agent asked something like “extend my project to use noodlelab so I can program with AI” or “make these calculations verifiable”. Each step is small and keeps the project working. Stop after any of them if the user only wants that much.

1. Install and set up the agents

uv add noodlelab            # or: pip install noodlelab, or add it to requirements.txt
noodlelab init-agent        # AGENTS.md section, CLAUDE.md import, skill, .mcp.json

init-agent can be run again safely: it updates its own section of AGENTS.md and leaves the rest of the file alone. Commit what it wrote so that every agent and every person working on the project gets the same rules. Codex CLI users also run codex mcp add noodlelab -- noodlelab mcp.

2. Find the calculations that matter

Look for code whose numbers someone relies on:

  • physical formulas;

  • constants with units in their names (speed_mps, mass_kg, # in metres), and retyped physical constants (3e8, 6.674e-11, 9.80665);

  • tolerances, thresholds and limits (if margin < 3:);

  • results written to reports, dashboards or files for other people.

List them for the user, and suggest starting with the one whose error would cost the most.

3. Put units and uncertainty on the inputs

Replace bare floats at the edges (config, constants, measured data) with quantities. Keep the function bodies as they are: Pint quantities go through ordinary arithmetic and NumPy.

# before
GRAVITY = 9.81  # m/s^2


def fall_time(height_m):  # returns seconds
    return (2 * height_m / GRAVITY) ** 0.5


# after
import noodlelab.verify as nv

GRAVITY = nv.measure("9.81 ± 0.02 m/s^2", name="g")  # source: local survey 2024


def fall_time(height):
    return (2 * height / GRAVITY) ** 0.5  # a quantity in seconds, with its uncertainty

A physical constant is not a measurement, so it doesn’t need a survey. Take it by name instead of retyping its digits, with its unit and (for measured ones such as G) its CODATA uncertainty:

from noodlelab.constants import G, c, g0  # `noodlelab constants` lists them all

SPEED_OF_LIGHT = 299_792_458  # m/s   ->   SPEED_OF_LIGHT = c
STANDARD_G = 9.80665  # m/s^2         ->   STANDARD_G = g0  (not the local g above)

Project-wide values that everyone should share (a reference density, a site’s surveyed gravity) go in a constants.toml at the workspace root, which graphs read automatically, and scripts load with nv.load_constants(...).

Where the code must hand plain numbers to a library, convert at the boundary with value.m_as("s") (the magnitude in seconds). Don’t strip units any earlier than that.

If you don’t know a value’s uncertainty, ask the user or look for it in a datasheet, calibration certificate or paper. Never invent one. An assumed value is recorded as source="assumed: ..." and listed for the user.

4. Write the requirements down

Put them where people will read them, for example requirements.txt-style in spec/requirements.txt or next to the code, one per line:

PER-001 period <= 2.1 s [Analysis]        # The swing shall take at most 2.1 s
TMP-001 temperature between -20 and 60 degC [Test]

Load them with nv.requirements(Path("spec/requirements.txt").read_text()). CSV or YAML rows (id, quantity, op, limit, unit, text, method) work too.

5. Record and verify each calculation

Wrap the entry point (a script, a CLI command or a pipeline step) in a record:

def main():
    with nv.record("pendulum sizing") as rec:
        L = rec.input("L", cfg.length, source="design v3")
        T = rec.result("period", period(L))
        rec.require(Path("spec/requirements.txt").read_text())
        rec.verify("PER-001", T)
    return 0 if rec.passed else 1

Mark helper functions whose calls should be in the audit trail with @nv.traced.

6. Check it in CI and in tests

# .github/workflows/verify.yml (a step)
- run: uv run noodlelab verify scripts/sizing.py --json
# tests/test_sizing.py
import noodlelab.verify as nv


def test_period_meets_its_requirement():
    with nv.record("test", write=False) as rec:
        rec.verify("PER-001 period <= 2.1 s", period(nv.q("1 m")))
    assert rec.passed, rec.summary()

Graphs are checked the same way: noodlelab verify analysis.graph.json. For checks plus regression against a run marked final, use noodlelab test *.graph.json --baseline final.

7. Optional: graphs and reports

If the user wants a visual pipeline or a PDF report, build it as a graph with the MCP tools (see graphs-and-reports.md). The user opens it with uvx "noodlelab[full]" . and sees the same analysis as nodes.

Report back

Tell the user:

  • what now carries units and uncertainty;

  • which requirements are verified, with their margins;

  • what was assumed, and which audit warnings remain;

  • where the records are (runs/, which may belong in .gitignore).