Skip to content
copperhead.sh
Get started

Reference

CLI

Every fang command.

Every command exits non-zero when the work it names did not succeed, so a build script can rely on the exit code rather than parsing output.

CommandDoes
fang initCreate a .copperhead/ workspace
fang buildElaborate, pass the gate, persist, run the tool plan
fang checkRun the constraint, topology and compatibility checks
fang netlistPrint the compiled components and nets
fang exportWrite a KiCad netlist
fang viewCompile a view; render it to SVG with -o
fang schematicCompile a KiCad schematic; render it with --svg, or have copperhead draft it
fang simCompile a simulation plan, lower it, run it
fang verifyRoute and run every declared question; persist only with --commit
fang emulateRun the firmware in Renode and print what each emulation question measured
fang graphSummarize the kernel graph
fang diffDiff a program against the persisted workspace
fang mcpServe the kernel to an agent over the Model Context Protocol, on stdio

Every command that reads a program takes the same four:

OptionDefaultDoes
programrequiredThe Fang program to elaborate
--systemfirst foundWhich system, when a file defines several
--projectPRJ-LOCALThe project identifier
-C, --directory.The project directory

--project is the namespace identifiers are derived in, so changing it changes every identifier in the design. It is not a label.

fang init takes only -C. fang --version reports the version.

CodeMeans
0The work succeeded
1The work failed: a rejected gate, a failed check, a missing model or a failed verification
2Usage error

A rejected commit is exit 1, and the diagnostics that explain it go to output. The rejection is the answer, not a crash.

Terminal window
fang view --list
fang view board.py ground -o ground.svg

The six views are system, interconnect, power, ground, interfaces and safety. interconnect is the default when none is named.

Each answers one engineering question and is generated only from facts in the graph. Each also reports its own incompleteness rather than hiding it: a node carrying unknown parameters is drawn with a dashed border.

Terminal window
fang schematic board.py -o board.kicad_sch --svg board.svg
fang schematic board.py --drafter copperhead -o board.kicad_sch
OptionDefaultDoes
-o, --outputstdoutWhere to write the .kicad_sch
--svgnoneAlso render the sheet here, with kicad-cli
--drafterfangWho draws the sheet: fang, a grid joined by labels, or copperhead, placed and wired

fang’s own sheet needs no tool; --svg needs kicad-cli. A copperhead draft needs copperhead and kicad-cli: the sheet is read back with KiCad and returned only if its nets are exactly the design’s, and refused, naming the difference, otherwise.

copperhead draws with KiCad’s library symbols, and fang picks each part’s in this order:

  1. The symbol the part names itself, symbol = "library:name", on the pins its own numbers name.
  2. The symbol its type is drawn with, where one prefix does not pick it out: an OpAmp is KiCad’s generic Simulation_SPICE:OPAMP, a Zener is Device:D_Zener.
  3. For a ground marker, a part whose every pin is a ground pin, KiCad’s power:GND; its net is declared a ground net.
  4. The symbol its designator prefix names: R, C, L, D, TP and the rest.

Where a symbol numbers its pins differently from the part, fang places each pin by name: a diode’s cathode goes on pin 1 of KiCad’s diode, and an op amp’s IN+, IN- and OUT on 1, 2 and 5. A part with no KiCad symbol, a part with a pin its symbol has no place for, or a net left with fewer than two drawn pins, is reported as a loss rather than dropped silently.

The textbook figures under examples/ are drafted from the same lowering, fang.copperhead.compile_intent, called from Python with options that change only the labels: the ground net’s name, terminals labelled with their names in the program, values printed short (10k for 10 kOhm), and the title block’s date. The command passes none of them, so it keeps the netlist’s names and values and leaves the date empty.

Terminal window
fang mcp board.py

Serves the kernel over the Model Context Protocol on stdio, bound to the project directory, with the agent’s changes going through the same commit gate as everything else. It needs the mcp extra, pip install "copperhead-fang[mcp]", and refuses with MCP-0005 without it.

Terminal window
fang sim board.py --analysis transient --stop 10ms --step 1us --probe "V(1)"
fang sim board.py -o deck.cir
OptionDefault
--analysisop (or transient)
--backendngspice
--stop1ms
--step1us
--probenone; repeatable
-o, --outputwrite the SPICE deck here

If a selected component has no compatible model and is not explicitly abstracted, the plan is rejected with the reason rather than run with a substitute. If ngspice is not installed, the plan still compiles and the command says no run was made.

fang sim is the low-level command: it runs a deck and reports the run, and nothing it finds reaches the graph. To answer a question and decide the constraint over it, declare the question and use fang verify.

Terminal window
fang verify board.py # route and run every question
fang verify board.py --commit # and persist the measurements
OptionDefaultDoes
--commitoffPersist the new head into the existing workspace

Each declared question is routed to the cheapest level that decides it and printed with its level, its tool, its measurements and its result, or the reason it did not run. A failed verification exits 1, and so does a question the program left unrunnable; a tool that is not installed is reported unsupported, by name, and is not by itself a failure. A program with no question says there is nothing to verify and exits 0.

Without --commit nothing is written, not even a scratch deck. --commit needs a workspace, so run fang build first. It persists measurements and nothing else: where the program has changed since that build, it refuses before anything runs and exits 1, saying to run fang build again. A model or firmware file changed since a run is not a change to the program, and its question runs again and is committed. See Verification.

Terminal window
fang emulate board.py
fang emulate board.py -o bundles
fang emulate board.py --bundle-only -o bundles
OptionDoes
-o, --outputWrite each question’s bundle into a folder of its own here
--bundle-onlyWrite the bundles and run nothing

fang emulate is the low-level command, as fang sim is for SPICE: it prints what each measure read and takes nothing through the gate, and it changes no workspace. fang verify answers emulation questions with every other kind and takes the measurements back through the gate. A question the program left unrunnable exits 1, and so does a run that timed out or crashed, whose measures have no value. Without Renode 1.17.0 on the path, each question is reported unsupported and nothing is fabricated, which is not by itself a failure. See Emulation.