flow5ctl
AI-driven aircraft design with flow5.
flow5ctl lets an AI agent — Claude Desktop, Claude Code, Codex, or any MCP client —
design and analyse low-Reynolds-number aircraft by driving flow5's headless batch engine.
It ships as one Python package with two front-ends:
| Front-end | Command | For |
|---|---|---|
| MCP server | flow5ctl mcp |
Claude Desktop, and any MCP-capable client |
| CLI | flow5ctl <verb> |
Claude Code, Codex, humans, CI |
13 tools, 7 resources and 4 prompts over MCP; the same capabilities as CLI verbs. Both are thin adapters over one core, so neither can drift ahead of the other.
Status: the CLI and the MCP server both work.
Claude Desktop can design an aircraft with this today — see docs/MCP.md for the one-line install. flow5ctl computes the geometry, generates and validates flow5's XML, computes 2D airfoil polars and caches them, drives the solver through the two passes it requires, solves trim conditions, runs parameter studies, and draws charts. 276 tests, 19 of them against a real flow5 7.57. Phases 1–3 of the roadmap are done.
macOS only. Verified against flow5 7.57 on macOS, and that is the only platform it is offered for. Nothing in the package is platform-specific, but every measured claim in
docs/was made on macOS, and this project's failure mode is confident wrong numbers — so Linux and Windows are stated as unverified rather than assumed to work. The verification log records what was found on the way, including a reproducible flow5 crash and seven ways its output misleads a naive reader; re-run any of it frompoc/.
日本語版 README: README.ja.md / はじめかた: docs/ja/QUICKSTART.md
Why
flow5 is an excellent potential-flow solver, but designing an aircraft with it is a long loop of manual GUI work: draw a planform, pick airfoils, set up a polar, run, read graphs, adjust, repeat. That loop is exactly what an AI agent is good at — if it can drive the solver reliably.
It can. flow5 has a headless batch mode (flow5 -s script.xml) that runs a full
plane analysis in well under a second. What it lacks is a surface an agent can
actually use: the XML schemas are large, some required fields are silently fatal if
omitted, and the results come back as wide Unicode-headed CSVs.
flow5ctl is that missing surface. It is not a thin wrapper around the flow5
binary — that would add nothing over a shell command. It is a domain layer that:
- accepts a high-level design description (span, taper, airfoil, mass, CG) instead of raw XML
- computes the geometry flow5 needs but does not derive in batch mode (reference area, span, MAC)
- generates and validates every XML artifact
- runs the solver, diagnoses failures in plain language
- returns summaries an agent can reason about (CL slope, best L/D and where, Cm_α, static margin, neutral point) rather than raw data dumps
- keeps the whole design in a git-friendly project directory so humans can inspect, diff and review it
How much of that is real work rather than plumbing: flow5 segfaults if one script
asks for both 2D and 3D work, its polar .csv files contain no commas, the first row
of data is welded onto the header line, Static margin is a percentage that looks
like a fraction, operating-point files are duplicated into every polar's directory
carrying another polar's contents, and a stability request on the wrong polar type
returns eigenvalues of 5.995e+51 with a straight face. Each of those is verified,
documented, and handled.
Who it is for
flow5ctl targets the whole low-Re community that already uses flow5 / XFLR5:
- Human-powered aircraft (鳥人間コンテスト, Daedalus-class): 30 m+ span, AR ≈ 30, Re ≈ 5×10⁵–1×10⁶, ground effect, spanwise loading, structural mass budget
- RC gliders (F3B / F3F / F5J, DLG): 1.5–4 m span, Re ≈ 5×10⁴–3×10⁵, camber-changing flaps, ballast, wide speed range
- Small UAVs and model aircraft in the same regime
Presets encode the defaults each of these needs; the underlying model is general.
Quickstart — Claude Desktop
Install flow5 from flow5.tech, then add one entry to Claude Desktop's config:
{
"mcpServers": {
"flow5": {
"command": "uvx",
"args": ["--from", "flow5ctl[plot]", "flow5ctl", "mcp"]
}
}
}
Restart, and ask: "Design a 3 m F5J glider for minimum sink, then show me what moving the CG from 30 % to 40 % MAC does." Full setup notes, including where designs are kept and how to point flow5ctl at an unusual flow5 install, are in docs/MCP.md.
Quickstart — command line
Install flow5 first, from flow5.tech. Then:
git clone https://github.com/97kuek/flow5ctl && cd flow5ctl
uv sync # or: pip install -e .
uv run flow5ctl doctor # check the flow5 installation
flow5ctl 0.1.0.dev0
flow5 7.57 /Applications/flow5.app/Contents/MacOS/flow5
verified
workspace ~/flow5ctl (writable)
presets custom, hpa, rc-glider, uav
Describe an aircraft, then analyse it:
# glider.yaml
preset: rc-glider
requirements: {cruise_speed: 12.0, objective: min_sink}
mass:
components:
- {tag: fuselage, mass: 0.40, at: [ 0.12, 0.00, 0.00]}
- {tag: wing_left, mass: 0.10, at: [ 0.05, -0.75, 0.02]}
- {tag: wing_right, mass: 0.10, at: [ 0.05, 0.75, 0.02]}
airfoils:
- {name: AG35, source: 'naca:2409'}
wing:
airfoil: AG35
planform: {span: 3.0, root_chord: 0.24, taper: 0.55, dihedral: 3.0, washout: -1.5}
flow5ctl init Glider --example rc-glider # or --file path/to/your.yaml
flow5ctl analyze Glider --type T1 --speed 12 --alpha=-2,8,2
The 2D airfoil polars it needs are computed automatically the first time and cached afterwards, so the first run takes about twenty seconds and later ones under a second.
Every report says what its lift-to-drag figure excludes — a VLM run of a wing and a tail returns the drag of a wing and a tail, and on a human-powered aircraft the rigging and the fairing are a fifth to two fifths of the aeroplane again. It also reports the wing root bending moment, which is the number a spar is sized from, with a closed-form cross-check beside it — and says when the operating point it came from is not level flight, because a fixed-speed polar's best-L/D point usually is not.
For an aircraft that flies in ground effect, one call does both:
flow5ctl analyze Albatross --compare-ground --ground-height 2.0
Run on examples/hpa.yaml, so you can reproduce it:
free air in ground change
best L/D 41.18 50.44 +22.5 %
min sink m/s 0.1729 0.1337 -22.7 %
CL_alpha /deg 0.10748 0.11128 +3.5 %
Solve, don't sweep
flow5ctl trim Glider --target level --speed 11 # α for level flight
flow5ctl trim Glider --target static-margin --value 0.10 # CG for a 10 % margin
flow5ctl trim Glider --target pitch --speed 11 # elevator incidence for Cm = 0
Solved
cg_x 0.07571
static_margin 0.1006
neutral_point_x 0.09476
shift_from_current 0.02821
A static margin of +10.0% needs the CG at x = 0.0757 m (39.7 % MAC), which is
28 mm aft of the current CG. The neutral point is at x = 0.0948 m.
That one takes two solver runs rather than a bisection, because the neutral point does not move with the CG — verified, so the second run only confirms the answer.
Compare
flow5ctl sweep Glider --parameter cg_x --values 0.04:0.09:6 \
--metrics static_margin,trim_alpha,ld_at_trim
cg_x static_margin trim_alpha ld_at_trim
----------- ------------- ----------- -----------
0.04 0.3448 -0.368 4.466
0.06 0.24 -0.001 6.485
0.08 0.1351 0.924 11.14
0.09 0.0827 2.286 17.297
ld_at_trim, not best L/D: moving the CG does not change the drag polar at all, only
where the aircraft trims. Ask for best_LD in a CG sweep and flow5ctl will tell you
the column is blind to the parameter you varied.
Studies are files, so a question survives a design change:
flow5ctl sweep Glider --study cg-sweep
Released:
pip install flow5ctloruvx --from "flow5ctl[plot]" flow5ctl— pypi.org/project/flow5ctl. macOS only.
Claude Desktop — add to your MCP config:
{
"mcpServers": {
"flow5": { "command": "flow5ctl", "args": ["mcp"] }
}
}
Then ask: "Design a 3 m F5J glider for minimum sink, and show me the effect of moving the CG from 30% to 40% MAC."
How it works
design.yaml ← source of truth, human- and LLM-readable, in git
│
flow5ctl │ geometry solve → XML generation → validation
▼
plane.xml + polar.xml + script.xml ← build artifacts, disposable
│
▼
flow5 -s script.xml ← headless, ~0.5 s per sweep
│
▼
polars.csv + oppoints/ + project.fl5
│
flow5ctl │ parse → normalise → summarise
▼
structured result + warnings → agent
→ `flow5ctl open` hands the .fl5 to the GUI for a human
The YAML is the source; the XML is a build artifact. See docs/ARCHITECTURE.md.
Drawn from the import graph, not from these notes — the editable source is docs/architecture.drawio, regenerated by tools/gen_architecture.py. A Japanese walkthrough of the same picture is in docs/ARCHITECTURE-ja.md.
Documentation
| Document | What it covers |
|---|---|
| docs/ARCHITECTURE.md | Layers, data flow, why one core with two front-ends |
| docs/ARCHITECTURE-ja.md | 日本語の全体像。アーキテクチャ図つき |
| docs/ja/QUICKSTART.md | 日本語のはじめかた。ターミナル未経験者向け |
| docs/ja/DESIGN-GUIDE.md | 日本語の設計ガイド(DESIGN-GUIDE.md の全訳) |
| docs/DOMAIN-MODEL.md | Vocabulary and the design.yaml schema |
| docs/MCP.md | Setting up Claude Desktop, and how to read what comes back |
| docs/MCP-TOOLS.md | The tool surface exposed to agents |
| docs/FLOW5-INTERFACE.md | Verified reference for flow5's batch/XML interface |
| docs/DESIGN-GUIDE.md | Aerodynamic guardrails agents must respect |
| docs/ROADMAP.md | Phases and milestones |
| docs/adr/ | Architecture decision records |
| docs/log/ | Investigation and verification log |
| poc/ | The verification harness — reproduce every measured claim |
| examples/ | Worked designs: an RC glider, an HPA, and a study |
Source layout: src/flow5ctl/{model,geometry,advisor} is the domain and never imports
src/flow5ctl/flow5, which is the only code that knows flow5 exists. usecases/
orchestrates; cli.py is a thin adapter over it, and the MCP server will be a second
one.
Contributing: CONTRIBUTING.md · Working with AI agents in this repo: AGENTS.md
Known limitations
- Induced drag depends on the wake length, and flow5's default is too short for a
slender wing. flow5 carries its wake 30 × MAC downstream, which is
30 / ARspans — 0.75 spans at AR 40 — and the induced drag comes out low as a result. flow5ctl sets the wake in spans instead (20 by default), which brings an elliptic wing to within 0.23 % of its exact span efficiency of 1.0 at every aspect ratio from 10 to 50, and matches AVL to 0.2 %. 0.1.0 shipped this the other way round, as a claim that flow5's induced drag is systematically wrong; it is not, and the correction is recorded. - Flaps and control surfaces are not supported, and cannot be. flow5 has no flap
or hinge elements in its plane XML — a flap belongs to flow5's Foil object, which a
.datfile cannot carry, and planes loaded from a GUI-made project cannot be paired with new analyses. So T6 control polars are out of reach through this interface. This matters if you fly camber-changing RC gliders; see the verification log, findings 9 and 10. - macOS only. Linux and Windows are unverified and not claimed. The package is
pure Python and has no platform-specific code, so it may well work — but flow5's
behaviour is what this tool encodes, and none of it has been measured on another
platform.
poc/verify_platform.pychecks every documented behaviour in one command and prints a pasteable report; a run from a Linux or Windows user is what would change this. - flow5's own defects are inherited. Dutch-roll and short-period frequencies are unreliable in 7.57 and are deliberately not reported.
Relationship to flow5
flow5 is a separate project by André Deperrois, released under GPL-3.0 at
techwinder/flow5. flow5ctl is an
independent tool that invokes the flow5 executable as a subprocess. It does not
link flow5 code and does not redistribute it — you install flow5 yourself.
See ADR-0006.
flow5ctl is not affiliated with or endorsed by the flow5 project.
License
Apache-2.0 (proposed — see ADR-0006).
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flow5ctl-0.1.9.tar.gz.
File metadata
- Download URL: flow5ctl-0.1.9.tar.gz
- Upload date:
- Size: 885.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05f80da817f64b53946186b2537b68abb1138f61ccaff5df76351ad294f6110d
|
|
| MD5 |
af9fa3c54819bd3c64468226ee9aec0e
|
|
| BLAKE2b-256 |
4ae6bacee6c62757593a6c2babb91b69c756799d59009088e81a3ee89cc446b8
|
Provenance
The following attestation bundles were made for flow5ctl-0.1.9.tar.gz:
Publisher:
release.yaml on 97kuek/flow5ctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flow5ctl-0.1.9.tar.gz -
Subject digest:
05f80da817f64b53946186b2537b68abb1138f61ccaff5df76351ad294f6110d - Sigstore transparency entry: 2712355158
- Sigstore integration time:
-
Permalink:
97kuek/flow5ctl@9e0a4d27fe008fd8460a91c1af7596a2119e85ec -
Branch / Tag:
refs/tags/v0.1.9 - Owner: https://github.com/97kuek
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@9e0a4d27fe008fd8460a91c1af7596a2119e85ec -
Trigger Event:
push
-
Statement type:
File details
Details for the file flow5ctl-0.1.9-py3-none-any.whl.
File metadata
- Download URL: flow5ctl-0.1.9-py3-none-any.whl
- Upload date:
- Size: 171.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e12c0e911f84900f09c46484504360fd9182ca4a4602eb57a827ec7e3de3f10e
|
|
| MD5 |
0722e1451016c652cb703ff9cbaaefea
|
|
| BLAKE2b-256 |
89b84509e9ce8f06cc9e0146a37064e2c5835dfca1dc2478f4f386a9b551ee41
|
Provenance
The following attestation bundles were made for flow5ctl-0.1.9-py3-none-any.whl:
Publisher:
release.yaml on 97kuek/flow5ctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flow5ctl-0.1.9-py3-none-any.whl -
Subject digest:
e12c0e911f84900f09c46484504360fd9182ca4a4602eb57a827ec7e3de3f10e - Sigstore transparency entry: 2712356651
- Sigstore integration time:
-
Permalink:
97kuek/flow5ctl@9e0a4d27fe008fd8460a91c1af7596a2119e85ec -
Branch / Tag:
refs/tags/v0.1.9 - Owner: https://github.com/97kuek
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@9e0a4d27fe008fd8460a91c1af7596a2119e85ec -
Trigger Event:
push
-
Statement type: