AGENTS.md

Notes for AI coding agents (Claude Code, Codex CLI, Cursor, Copilot and others). There are two cases: using noodlelab in someone’s project, and working on this repository.

Using noodlelab in a project

noodlelab makes calculations verifiable. Every number carries its unit and uncertainty, requirements are checked with margins, and every run leaves a provenance record. When a user asks you to “use noodlelab”, “make this verifiable”, or to build a noodlelab graph or report:

  1. pip install noodlelab, or uv add noodlelab (the library: noodlelab.verify). Add [app] for the browser editor, and [full] for every node pack.

  2. Run noodlelab init-agent in the project. It writes an AGENTS.md section, a CLAUDE.md import, a skill (.claude/skills/noodlelab/SKILL.md) and the MCP server in .mcp.json. For Codex, run codex mcp add noodlelab -- noodlelab mcp.

  3. Read src/noodlelab/agent/guide.md (the MCP guide tool returns the same text). It has the rules, the Python API, the graph format and the workflow.

  4. Before saying you are done, run noodlelab verify <script.py | graph.json> --json. Exit code 0 means every check passed and every requirement was verified.

Recipes:

Working on this repository

uv sync --all-extras            # Python env with every pack and the dev tools
cd frontend && npm ci && cd ..  # editor dependencies
make test                       # uv run pytest -q (parallel; -n0 for serial)
make lint                       # ruff check + ruff format --check + tsc
make frontend                   # build the editor into src/noodlelab/static
make docs                       # the docs site (uv sync --all-extras --group docs first)

CI (.github/workflows/ci.yml) runs lint and tests on Python 3.11–3.13, the frontend build, and each installation tier on its own (scripts/check_tier.py). After changing a docstring, a node or the guide, run uv run python scripts/gen_llms.py (a test fails when llms.txt is stale). It also writes the skill into the Claude Code plugin (plugin/). After changing the skill’s description (SKILL_HEADER in src/noodlelab/agent/__init__.py), run its trigger evals: claude plugin eval plugin --ablation none --trust-plugin. Each case in plugin/evals/ is a prompt that never names noodlelab, and checks that the skill loads for a physical calculation and stays out of everything else. A run that stops at its turn limit after loading the skill still passes. The documentation site (docs/, Sphinx with MyST) is built from the same sources, so it needs no regenerating; CI builds it with warnings as errors, and docs.yml publishes it to GitHub Pages (see docs/releasing.md).

Map

Path

What

src/noodlelab/verify.py

noodlelab.verify: records, measure/q, requirements, audit, Monte Carlo check

src/noodlelab/core/

the engine, independent of the editor: graph model (graph.py), executor.py, units.py, uncertainty.py (GUM), constants.py (named constants), montecarlo.py (JCGM 101), requirements.py, checks.py, provenance.py, tracked.py / reqlog.py (run histories), registry.py, typesys.py

src/noodlelab/nodes/

the built-in node packs (entry points in pyproject.toml), one per tier

src/noodlelab/agent/

agent support: guide.md, the MCP server (mcp.py, tools.py), init-agent

src/noodlelab/server/

FastAPI app (app.py), REST API (api.py), WebSocket runs (ws.py), workspaces, auth, Slurm, agent terminal

src/noodlelab/reports/

Typst PDF reports

src/noodlelab/examples/

25 example graphs (*.graph.json) with data: the best reference for graph JSON

plugin/, .claude-plugin/marketplace.json

the Claude Code plugin (skill + MCP server) and its trigger evals

server.json

the MCP Registry entry, published by release.yml

src/noodlelab/cli.py

noodlelab serve / run / test / verify / mcp / init-agent / nodes / export ...

src/noodlelab/tiers.py

installation tiers (library, basic = [app], maths, science, engineering, geo, full)

frontend/src/

the editor: TypeScript + litegraph, no framework (main.ts wires everything)

docs/

the guides, and the Sphinx site: conf.py, _ext/noodlelab_docs.py (generated reference pages, link fixing)

tests/

pytest; conftest.py has the registry, packs and executor fixtures and the graph/link/value helpers

Conventions

  • Docstrings and comments are plain prose saying why. Modules open with a docstring that explains the concept (read core/graph.py and core/uncertainty.py for the style).

  • A node is a type-hinted function with @node. Its hints decide the sockets, units (Quantity["m"]) and widgets (Annotated[int, Param(min=1)]), and its docstring is the help text. A node pack checks its dependencies with noodlelab.tiers.require().

  • A node never changes its inputs in place. The executor freezes the arrays a node returns and hands out shallow copies of tables and lists (core/protect.py), so a node that writes to an input array fails loudly.

  • Anything that records history or provenance must never fail a run: catch, log, and carry on.

  • The bare library must not import the web server or typst at module level (CI’s library tier checks this).

  • Line length 100, ruff rules E, F, I, UP, B, SIM. TypeScript is checked with tsc --noEmit.

  • Tests describe behaviour in their names (test_a_run_without_requirements_records_nothing), and use real graphs through executor.run(graph(...)) rather than mocks.

This page is the repository’s AGENTS.md, which coding agents read when they work in it. noodlelab init-agent writes a shorter section into your own project’s AGENTS.md.