Idea to Reality
One sentence to a manufacturable product — enclosure, PCB and firmware, cross-checked and packaged. Use for any invent/build-me-a-device ask, or to drive it from a terminal or MCP client.
Idea to reality
One sentence in, three artifacts out, cross-checked. The pipeline derives requirements from the ask, re-derives its own plan from them, designs the board, sizes the enclosure around that board, writes firmware against that board's netlist, checks the three against each other, and assembles a work order for a machine that can actually make the part.
Everything is one adapter call. inventor.invent is the door; the six-stage gate loop lives behind it. Reach for the stage-by-stage API only when a person is approving each gate.
pnpm invent "A desk environment monitor: an ESP32 reading a BME280 over I2C, with a status LED
and a button, in a small printed enclosure." --provider cursor-agent
| flag | what it does |
|---|---|
--provider <id> | cursor-agent · codex · claude · openai · ollama · gemini. Name one for a reproducible run — auto can answer differently on two machines. |
--boot | boot an API in-process instead of talking to one. Needs no server; what makes this work on a clean checkout. |
--api <url> | an API already running (default http://127.0.0.1:3000, or LEUMAS_API_URL). |
--hold | stop at the first gate and print the plan instead of building. |
--export <dir> | write the finished geometry there as STL + 3MF, one file per part. |
--json | the result as JSON and nothing else, for a script. |
Exit code is 0 only when the run finished and every interface check passed.
From another agent — Claude Code, Codex, any MCP client
The adapter registry exposes every function as an MCP tool automatically, so nothing needs building:
# 1. mint a key (session-authenticated, once)
curl -s -X POST http://127.0.0.1:3000/keys -H 'content-type: application/json' \
--cookie "$LEUMAS_COOKIE" -d '{"name":"invent","scopes":["mcp"]}'
# 2. point the client at the gateway
claude mcp add --transport http leumas http://127.0.0.1:3000/mcp/rpc \
--header "Authorization: Bearer lk_…"
Then call inventor__invent with {brief, provider}. The gateway flattens all 190 adapter systems into one server and namespaces tools <system>__<fn>, so ~1,800 tools arrive at once — which is exactly why invent exists as a single call. For a curated server, create an Imperium config with mode: 'mcp' selecting adapter:inventor.* and connect to /mcp/s/<configId> instead.
Codex and any other client work identically: the pipeline hands every provider the same typed grammar and makes every adapter call itself, so none of this needs tool-calling support from the model. toolloop.js gates tools on provider.capabilities.tools, and cursor-agent is tools: false — that constraint is why the design is a grammar rather than an agent loop, and why it is portable.
What comes back
product <product-ir> the requirements, and what covers each one
board <circuit-ir> spec · netlist · BOM · verdict · readiness
enclosure <design-ir> features · parts · walls · cavities · mounts · ports · measured stats
firmware <software-ir> source · pin map, resolved against the netlist
package <build-package> plates · BOM · assembly steps · the machine command
Plus interfaces: {checked, passed, failing, skipped}. Read skipped — a check nobody could assemble is not a check that passed, and it names what was missing.
The five interface checks
Derived by product-compiler.deriveInterfaces from the three stored documents. Every number is measured; every threshold is a declaration and none is ever invented, because a check with a made-up threshold passes and means nothing.
| check | what it proves |
|---|---|
board-fits-enclosure | the board's clearance envelope is a volume-intersection fit inside the measured cavity |
mount-alignment | every hole has a boss and every boss has a hole — the direction nobody else checks |
connector-cutouts | every external connector has an opening in the wall it faces, sized for the plug |
pin-map-matches | every firmware pin exists on the board, on the net the firmware thinks, in a direction the part can do |
bom-complete | one bill of materials covers every made part, every component and every fastener |
The rules that make it work first try
Everything below is algorithmic — computed and handed to the model, never left to its judgement. Each one was added because its absence produced a specific, repeatable failure.
- The board is designed first.
defaultPlanorders electronic → mechanical → software; the later
two read the board. An enclosure sized before the board exists is sized for a guess.
- The cavity arithmetic is computed ("at least W+2c × D+2c × stack+2c") and put in the prompt.
- The connector rectangle is computed (body + 2× plug clearance), and the wall frame —
[u,v]
from the CENTRE of the face — is stated in both grammars. Two frames for one number put a cutout 50mm from its socket.
- The pin table is resolved. A netlist says
U1.GPIO4;pinMode()takes4.mcuPads()in
@leumas/reality-compiler/pinMap.js is the one bridge, and an ambiguous number is dropped rather than guessed.
- The parts library is in the prompt. A chip whose
valueis not a library id is refused as an
unknown pinout, so guessing costs a round trip. circuit-studio.parts is the door.
- A refusal is fed back verbatim,
detailsand all. Told only that something failed, a model
guesses and burns the retry on the wrong fix.
What it refuses, and why that is the feature
- A stage that refuses fails the run. A refusal recorded as
doneis the most expensive lie a
pipeline can tell — indistinguishable from success in every count.
- Firmware naming a pin the board does not route is not stored (
pins-not-routed), and the
correction carries the right number.
- A board whose electrical rules fail is not stored. A stored artifact is one later passes trust.
- A part with a guessed pinout cannot be exported.
provisional→derived→verified; only a
human promotes to verified.
- A brief needing a part nobody has entered is refused, not approximated. Add it with
circuit-studio.importParts (which requires a source) or put an inline pins map with a pinSource on the component.
Proving it
pnpm smoke:one-prompt # the simple brief, once
pnpm smoke:one-prompt --brief hub --runs 3 # a harder board, three times, with a rate
pnpm smoke:one-prompt --brief all # every preset
pnpm smoke:one-prompt --provider codex # any brain
Three presets that climb: monitor (one MCU, two peripherals) · hub (a regulated rail, four peripherals, two buses) · array (dozens of emitters behind buffers). Every part in all three is already in the library, so what is measured is the pipeline, not the parts catalogue. The tail of the run is a consistency table and a first-try rate.
Without a provider the smoke skips loudly — except the anti-green-tick assertion, which always runs.
Where the code is
| the engine | shared/engines/inventor/ — decompose · loop · stages · contracts |
| the IR contract | shared/packages/reality-compiler/ — 12 kinds, hashing, lineage, the interface tables |
| the geometry | shared/engines/generation/.../cad/kit/ — evaluator, joinery, exporters, interfaceCheck |
| the adapters | inventor · product-compiler · cad-compiler · circuit-studio · fabrication-plan |
| the CLI | ops/tools/invent/index.mjs |
Deeper: leumas-circuits for boards, leumas-capabilities for what exists and how to wire more in.
Gerbers
The adapter lane produces source, netlist, BOM and a verdict. Real fab files are produced in the browser by buildFabPackage, reachable headlessly:
node ops/tools/circuit-check/index.mjs --export
That is the only lane that yields Gerbers, Excellon, BOM CSV and pick-and-place, because they are made from the evaluated circuit graph and nothing on the server side has one.