# Foam-Agent: a multi-agent pipeline that writes and runs OpenFOAM cases from a prompt

> Foam-Agent turns a natural language description of a CFD problem into a complete OpenFOAM case, runs it, and retries on failure. It is built for engineers who know the physics but not the dictionary syntax, and it depends heavily on which LLM you point it at.

**csml-rpi/Foam-Agent** — Foam-Agent: An end-to-end, composable multi-agent framework for automating CFD simulations in OpenFOAM. NeurIPS 2025 Machine Learning and the Physical Sciences Workshop.

- Repository: https://github.com/csml-rpi/Foam-Agent
- Website: https://arxiv.org/abs/2505.04997
- Stars: 332 · Forks: 73
- Language: Python
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/csml-rpi-foam-agent

## The gap Foam-Agent targets: physics knowledge versus OpenFOAM dictionary syntax

OpenFOAM cases are directories of dictionaries. A working pitzdaily run needs blockMeshDict, controlDict, fvSchemes, fvSolution, and one file per boundary patch, and each of those has its own grammar. The physics is often the easy part. Remembering whether a keyword sits under divSchemes or gradSchemes is not.

Foam-Agent's premise is that an LLM plus a retrieval index plus a retry loop can produce that directory from a paragraph of prose. The README's own example prompt specifies a RAS pitzdaily case, PIMPLE, a 2D millimetre channel, 10 m/s inlet, zero gradient pressure outlet, no-slip walls, timestep 0.0001, write interval 0.01, final time 0.3, and nu of 1e-5. Everything a solver needs is in that paragraph, which is the point: the user states the setup and the framework translates it.

The audience is therefore narrower than "CFD engineers". It is people who can already judge whether a generated case is physically sensible, and who want to skip the dictionary plumbing. Someone who cannot tell a bad fvSolution from a good one will not be able to audit the output.

## Architect, Input Writer, Runner, Reviewer: the four-agent loop and its 25-iteration ceiling

The README describes a LangGraph pipeline in which four agents collaborate. Architect plans the case. Input Writer produces the OpenFOAM files. Runner executes the solver. Reviewer inspects the result and feeds corrections back. The loop runs up to 25 iterations of automatic error correction.

The retrieval layer is what makes the Input Writer plausible. Hierarchical FAISS indices are built from OpenFOAM tutorials, so generation is conditioned on real tutorial files rather than on the model's memory of OpenFOAM syntax. The repository ships init_database.py and a database/ directory, which is consistent with that design: the index is a build artifact, not something that appears at runtime.

Input Writer has two modes, set through input_writer_generation_mode in src/config.py. sequential_dependency generates files in order and passes cross-file context, which the README recommends for expensive runs on HPC where a failed retry costs wall-clock time. parallel_no_context generates files in parallel with no cross-file context, recommended for fast local runs where retrying is cheap. That is a real trade-off stated plainly: consistency between files against latency.

The 25-iteration ceiling is the design's honest limit. A case that fails for a reason the Reviewer cannot diagnose will burn all 25 loops and stop. The README does not document what happens to partial output at that point.

## Installing Foam-Agent and running the pitzdaily case

The fastest path is the published Docker image, which the README says ships with OpenFOAM v10, Conda, and all dependencies. The container listens on port 7860 and expects an API key for whichever provider you choose. The default provider is openai, so OPENAI_API_KEY is the variable the quick start passes.

```bash
docker run -it \
  -e OPENAI_API_KEY=your-key-here \
  -p 7860:7860 \
  --name foamagent \
  leoyue123/foamagent
```

Inside the container, the workflow starts from a prompt file. The repository includes user_requirement.txt, and the README shows editing it and then invoking the entry point with an output directory and a prompt path.

```bash
python foambench_main.py --output ./output --prompt_path ./user_requirement.txt
```

If you would rather not use OpenAI, the provider and model are environment variables, and the README gives an Anthropic example. Note that ANTHROPIC_API_KEY replaces OPENAI_API_KEY in that invocation.

```bash
docker run -it \
  -e FOAMAGENT_MODEL_PROVIDER=anthropic \
  -e ANTHROPIC_API_KEY=your-key-here \
  -e FOAMAGENT_MODEL_VERSION=claude-opus-4-6 \
  -p 7860:7860 \
  leoyue123/foamagent
```

For a local install rather than Docker, the README's MCP section uses pip install -e . from the repository root, which registers the foamagent-mcp console script declared in pyproject.toml. Python 3.10 or newer is required. Embeddings default to huggingface with Qwen/Qwen3-Embedding-0.6B, which runs locally and needs no key, so the only mandatory credential is the LLM one.

What you should see after the run command is an output directory containing the generated case, plus the solver log from the Runner agent. The README states the framework will plan the case, generate all OpenFOAM files, run the simulation, and fix errors automatically.

## External Gmsh meshes and the boundary condition problem

Foam-Agent accepts external Gmsh .msh files in ASCII 2.2 format through the --custom_mesh_path flag, and the repository includes tandem_wing.msh with a matching user_req_tandem_wing.txt. Under Docker you mount the mesh into the container at a path under /home/openfoam/Foam-Agent/.

```bash
python foambench_main.py \
  --output ./output \
  --prompt_path ./user_req_tandem_wing.txt \
  --custom_mesh_path ./tandem_wing.msh
```

This is where the prompt carries more weight than it does for a blockMesh case. The README says to describe boundary conditions in your prompt, because the mesh file supplies geometry but not the physical roles of each patch. A tandem wing mesh with named patches is only useful if the prompt tells the framework which patch is the inlet, which is the outlet, and which is the wall. Get that mapping wrong and the case will still run, producing a plausible and incorrect answer. That failure mode is quiet, which makes it worse than a solver crash.

The mesh path also constrains you to ASCII 2.2. If your mesher emits a newer Gmsh format, converting it first is on you; the README does not describe a conversion step.

## MCP tools and the Claude Code skill: Foam-Agent as a component, not just a CLI

Version 2.0.0 introduced MCP support, and this is the part that changes how the project fits into a workflow. The core functions are exposed as MCP tools, so an agentic client can call the CFD workflow directly instead of shelling out to foambench_main.py.

For Claude Code the registration is a single command after a local install, and the README also documents a JSON block for Cursor and Windsurf that names foamagent-mcp as the command.

```json
{
  "mcpServers": {
    "foamagent": {
      "command": "foamagent-mcp"
    }
  }
}
```

In Docker the server runs over HTTP on port 7860, and the client config becomes a URL rather than a command.

```bash
docker run -it \
  -e OPENAI_API_KEY=your-key-here \
  -p 7860:7860 \
  leoyue123/foamagent \
  foamagent-mcp --transport http --host 0.0.0.0 --port 7860
```

The README notes that a remote Docker host needs port 7860 reachable, via SSH forwarding or the -p flag. It also mentions a Claude Code skill invoked as /foam for one-command runs. The practical consequence is that a simulation becomes a tool call inside a larger agent session, which is convenient and also means the boundary between "the model wrote my case" and "the model wrote my case and then reasoned about the results" gets blurry.

## The success rate depends on the model, and the spread is wide

The headline number in the README is a 100% success rate on FoamBench, which the README describes as 110 simulation tasks, achieved with Claude Opus 4.6. The table underneath it is the more useful document. At 25 loops, Opus 4.6 scores 100% on both basic and advanced tasks. Sonnet 4.6 scores 87.88% basic and 75.00% advanced. Haiku 4.6 scores 54.55% and 37.50%. gpt-5.4 scores 45.45% and 75.00%. gpt-5.3-codex scores 54.55% and 62.50%. At 10 loops Opus 4.6 drops to 85.45% basic.

Read that table as a cost curve, not a leaderboard. The difference between a 100% and a 45.45% basic success rate is the difference between a tool you can leave unattended and one you babysit. The README recommends Anthropic Claude Opus 4.6 for best results, and the numbers explain why: the retry loop cannot compensate for a model that misreads the case setup.

Two things the README does not give you. It does not say how long a run takes, so you cannot budget wall-clock time from the documentation. And it does not document rollback, so if a run produces a broken case directory there is no described mechanism to return to the previous state. The output directory is yours to manage.

There is also a fork question. Foam-Agent generates files following Foundation OpenFOAM v10 conventions by default. Setting FOAMAGENT_OPENFOAM_FORK=esi translates generated input files to ESI OpenFOAM naming and dictionary conventions, and the README qualifies this as best-effort. If your cluster runs ESI, that qualifier matters.

## How Foam-Agent differs from PyFoam and from writing the case yourself

The obvious alternative is not another LLM agent. It is PyFoam, the long-standing Python library for manipulating and monitoring OpenFOAM cases. The difference in approach is fundamental. PyFoam gives you programmatic control over a case you have already defined: it can clone a case, edit dictionary entries, launch a solver, and parse the log. It does not decide what the case should be.

Foam-Agent inverts that. You supply intent and it supplies the case. That is a much higher-leverage position when you are starting from nothing and a much worse one when you already have a validated setup that you want to sweep across a parameter range. For a parametric study, a template case plus PyFoam scripting is deterministic, cheap, and reproducible. Foam-Agent's output varies with the model and the retrieval context, which is exactly what you do not want when the only thing changing between runs should be the inlet velocity.

The second alternative is simply writing the dictionaries yourself. For a case you run once, an experienced OpenFOAM user will likely be faster by hand than by prompt, especially after accounting for the audit time. Foam-Agent pays off when the case is unfamiliar, when the geometry comes from an external mesh, or when you want a starting point that you then refine.

## Licence, maintenance and what an upgrade actually costs

Foam-Agent is MIT licensed, stated in both the LICENSE file and the license field of pyproject.toml. MIT is permissive, so the usual obligations apply: keep the copyright notice and the licence text with any redistribution. Nothing here restricts commercial use. That is a statement about the licence text, not legal advice about your situation.

The last push to the repository was on 2026-08-14, and the repository is not archived. The most recent release listed is v2.1.0 from 2026-04-01, following v2.0.0 on 2026-03-01 and v1.1.0 on 2025-10-24. The project is a research artifact tied to a NeurIPS 2025 workshop paper, and pyproject.toml classifies it as Development Status 4 - Beta. Treat it as beta software regardless of how the version numbers read.

Upgrade cost is dominated by the model dependency, not the code. pyproject.toml pins minimum versions for langchain, langgraph, faiss-cpu and the provider SDKs, and the recommended models in the README are recent enough that provider deprecations will move your success rate even if you change nothing in Foam-Agent itself. The 2.0.0 release notes name MCP and safer model and auth options as the headline changes, which is the shape of upgrade you should expect: new integration surfaces rather than solver-level fixes. If you pin a Docker tag such as v2.0.0 rather than pulling latest, you at least control when that moves.

## Conclusion

Foam-Agent fits teams that already run OpenFOAM and want a first draft of a case directory, plus a retry loop, without hand-writing every dictionary. It does not fit anyone who needs a guaranteed correct result on a novel setup, since the published success rates swing from 45.45% to 100% depending on the model, and the README shows Sonnet 4.6 and Haiku 4.6 scoring below Opus 4.6. Before adopting it, run the pitzdaily example with your own API key and confirm that the generated case matches the Foundation v10 conventions you actually use, or set FOAMAGENT_OPENFOAM_FORK=esi if your installation is ESI.

## FAQ

### What is Foam-Agent?

It is a multi-agent framework that automates the OpenFOAM CFD workflow from a natural language prompt, covering meshing, case setup, execution, error correction and post-processing. It is written in Python and released under the MIT licence.

### How do I install Foam-Agent and run a first simulation?

The quick start pulls the leoyue123/foamagent Docker image, which the README says includes OpenFOAM v10, Conda and all dependencies, then runs python foambench_main.py with an --output directory and a --prompt_path pointing at your requirement file. A local install is also possible with pip install -e ., which registers the foamagent-mcp command.

### Which LLM should I use with Foam-Agent?

The README recommends Anthropic Claude Opus 4.6, which the recommended-models table lists at 100% on both basic and advanced FoamBench tasks with 25 loops. The same table shows gpt-5.4 at 45.45% basic and Haiku 4.6 at 54.55% basic, so the provider choice has a large effect on results.

### Can Foam-Agent use a mesh I made in Gmsh?

Yes, it supports external Gmsh .msh files in ASCII 2.2 format, passed with the --custom_mesh_path flag. The README says you should describe the boundary conditions in your prompt, since the mesh supplies geometry but not the physical role of each patch.

### Does Foam-Agent work with ESI OpenFOAM instead of Foundation OpenFOAM?

It generates files following Foundation OpenFOAM v10 conventions by default. Setting FOAMAGENT_OPENFOAM_FORK=esi translates the generated input files to ESI naming and dictionary conventions, which the README describes as best-effort.

## Sources

- [csml-rpi/Foam-Agent on GitHub](https://github.com/csml-rpi/Foam-Agent)
- [License: MIT](https://github.com/csml-rpi/Foam-Agent/blob/main/LICENSE)
- [Project website](https://arxiv.org/abs/2505.04997)
- [README](https://github.com/csml-rpi/Foam-Agent/blob/main/README.md)
- [Releases](https://github.com/csml-rpi/Foam-Agent/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/csml-rpi-foam-agent
