The command line

dxcad is the widest door into DX-CAD: every operation the kernel has is reachable from it, no window is opened unless one is asked for, and every command reads and writes plain files. This page has one section per subcommand, in the order dxcad --help lists them, and each says what the command is for, what it takes, what it writes, every option it has and what it exits with. Each section closes with the command's usage line and its arguments, generated from the command itself by python -m dxcad.docsgen cli, so that part can never say other than what --help does.

Three statuses are used throughout, and they are the same in every command:

  • 0, the command did what it was asked.
  • 1, cli.UNSOUND: nothing was wrong with the command line, and the answer is no. Only validate, printability and doctor give it.
  • 2, cli.USAGE_ERROR: the command line, or a file it named, was wrong. Nothing is written and a line saying what went wrong goes to stderr.

A model that fails is a usage error too: the model's own traceback is turned into one line naming the model and the line in it that raised, never a traceback of DX-CAD's own.

The worked commands

Every section gives a command that can be pasted as it stands. They run in the order they are written, in one empty directory, and the test suite runs them there at every commit, so a command on this page is a command that works. These two come first and make the part the rest of them read:

Worked, exits 0:

dxcad examples bracket
dxcad run bracket.py --output bracket.dxcprt

info

What a project holds, in three columns: one line per entry with its name, its volume and whether it is a valid solid, then a last line naming the model the project carries and how long it is.

Takes a .dxcprt or .dxcasm project (an older .dxcad too), a .py model to run first, or - for a model on standard input. Writes nothing but its own output.

  • --timeout SECONDS stops a model that runs longer than this. No limit by default, and it is the same option, with the same meaning, wherever a command can be given a model.

Exits 0, or 2 when the file is not a project and not a model.

Worked, exits 0:

dxcad info bracket.dxcprt
usage: dxcad info [-h] [--timeout SECONDS] project
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

bounds

The bounding box of everything in a project, as two lines, min and max, in millimetres. What a print bed or a billet has to hold.

Takes what info takes. Writes nothing but its own output.

  • --timeout SECONDS, as everywhere.

Exits 0, or 2 when the file cannot be read.

Worked, exits 0:

dxcad bounds bracket.dxcprt
usage: dxcad bounds [-h] [--timeout SECONDS] project
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

validate

Whether every entry is a sound solid, and with --script whether the shapes in the file still agree with the model that is supposed to build them. It prints nothing when all is well, which is what a build step wants.

Takes what info takes. Writes nothing.

  • --script re-runs the model the project carries and compares what it builds with what is stored.
  • --tolerance TOLERANCE is how far a volume may differ from the model's, relative; 1e-06 by default.
  • --timeout SECONDS, as everywhere.

Exits 0 when sound, 1 when a solid is invalid or a volume disagrees, and 2 when the file cannot be read or the tolerance is not a number.

Worked, exits 0:

dxcad validate bracket.dxcprt --script
usage: dxcad validate [-h] [--script] [--tolerance TOLERANCE] [--timeout SECONDS] project
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • --script: also check the entries against the model.py the project carries
  • --tolerance TOLERANCE: how far a volume may differ from the model's, relative; 1e-06 by default
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

describe

Everything an agent needs to reason about a part without seeing it: per entry the volume and area, the bounds and size, the centre of mass, the faces by the kind of surface under them, the edges and vertices, and every round hole with its diameter, depth, axis and centre.

Takes what info takes. Writes nothing but its own output.

  • --name NAME describes that one entry; every entry by default, and a name the project does not have is a usage error.
  • --json prints the same facts as one JSON document, numbers unrounded, which is the form to pipe into something else.
  • --timeout SECONDS, as everywhere.

Exits 0, or 2 when the file cannot be read or the name is not there. An entry that is an unsound solid is said to be invalid and still exits 0.

Worked, exits 0:

dxcad describe bracket.dxcprt
usage: dxcad describe [-h] [--name NAME] [--json] [--timeout SECONDS] project
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • --name NAME: the one entry to describe; every entry by default
  • --json: print the same facts as one JSON document, numbers unrounded
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

serve

The agent door: an MCP server on standard input and output, one JSON-RPC message a line, holding one document of named parts. It is what agents.md is about, and every tool it offers is listed there.

Takes no file: the client speaks to it down a pipe. Writes only what a tool is asked to write, and only inside its directory.

  • --directory DIR is the directory the tools' paths are taken from and the only place the server may read or write. The directory it was started in by default, which is not somewhere a client chooses carefully.
  • --allow-run offers the two tools that exec a model.py with the user's own permissions. Without it the server has neither of them.
  • --config starts no server and prints the JSON an MCP client is configured with, naming this Python and this directory. On stderr it names the file --install would write.
  • --install starts no server either: it writes what --config prints into Claude Desktop's configuration file. On Windows that is the Microsoft Store edition's, under %LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude, when that edition is installed, and otherwise the one under %APPDATA%\Claude. On macOS it is under ~/Library/Application Support/Claude, and elsewhere under ~/.config/Claude. It keeps every other key the file holds, its other servers and its preferences alike, and copies the old file beside it with .bak added. It prints the path it wrote, and on stderr the backup's name. --directory and --allow-run go into the entry. A dxcad entry already there is replaced only with --force, and a file that is not JSON is left alone; either exits 1.
  • --config-file FILE is the file --install writes instead of Claude Desktop's own.
  • --force lets --install replace a dxcad entry.
  • --http serves the same tools over HTTP instead, on 127.0.0.1 only, at http://127.0.0.1:PORT/mcp: a JSON-RPC message is POSTed and answered as JSON. Every request carries Authorization: Bearer TOKEN, TOKEN being what DXCAD_TOKEN holds or one printed on stderr at start; without it, or with another, the answer is 401. The two tools that run Python need --allow-run-http as well as --allow-run.
  • --port PORT is the port --http listens on; 8765 by default.
  • --allow-run-http, with --allow-run, offers the run tools over HTTP.
  • --window [CHANNEL] drives the open DX-CAD window instead of a document of the server's own: every tool call is carried out on the window's document, one undo step each, and the window's model.py in its pane gains the statement for it, as a window action writes one: for the tools that make, move, drill, round or chamfer a part, the booleans, the patterns, the two sketch tools, and renaming, copying or removing a part. The first call takes the template's place, and undoing it puts the template back. For any other tool (hollow, the sheet metal tools, an import) the status bar says the model has no line for it and the part stays. A relative path a tool writes to is taken from the window's document folder when the document has been saved, else from --directory, else from the user's Documents folder; the answer gives the whole path as written, and the window's status bar says where the file went. A window that closes lets the server go on: while no window is open each tool call is refused saying so, and the next window that listens on the channel is found by the next call, with no restart. The window listens on a named pipe on Windows and a Unix socket elsewhere, never a network port, this user's channel unless CHANNEL names another. --allow-run still gates the two tools that run Python.

Exits 0 at the end of input, 1 when --window finds no window listening, or 2 when the directory is not there.

Not run by the test: a server waits on standard input, so it would never return; examples/bracket.md drives one from a file instead.

dxcad serve --directory .
usage: dxcad serve [-h] [--directory DIR] [--allow-run] [--window [CHANNEL]] [--config] [--install]
                   [--config-file FILE] [--http] [--port PORT] [--allow-run-http] [--force]
  • --directory DIR: work in DIR: the tools' relative paths are taken from it, since the client that starts the server chooses where and cannot be told
  • --allow-run: offer run_model and model_set, which exec a model.py with your own permissions; without this the server has neither tool
  • --window [CHANNEL]: drive the open DX-CAD window instead of a document of the server's own, over its local channel (this user's by default); fails at once with no window open
  • --config: start no server: print the JSON an MCP client is configured with, naming this Python and --directory's DIR, to paste into Claude Desktop's claude_desktop_config.json or Claude Code's .mcp.json
  • --install: start no server: write what --config prints into Claude Desktop's configuration, keeping its other servers and backing the old file up beside it
  • --config-file FILE: the configuration --install writes; Claude Desktop's own on this platform by default
  • --http: serve over HTTP on 127.0.0.1 only instead of standard input and output, every request carrying the bearer token DXCAD_TOKEN holds, or one printed at start
  • --port PORT: the port --http listens on; 8765 by default
  • --allow-run-http: with --allow-run, offer the two tools that run Python over HTTP too
  • --force: let --install replace a dxcad entry the configuration already has

printability

Whether each entry will print on a desktop printer: per entry the volume and the mass in the material given, the centre of mass, how many faces overhang further than the printer can manage and their area, the thinnest wall and where it is, and a warning for each check that fails.

Takes what info takes. Writes nothing but its own output.

  • --material MATERIAL is the filament, one of PLA (1.24 g/cm3), PETG (1.27), ABS (1.04), ASA (1.07) and TPU (1.21), in any case; PLA by default. The mass line names the material and density it assumed.
  • --density DENSITY is the density in g/cm3 of a filament not in that list, instead of --material.
  • --min-wall MIN_WALL is the thinnest wall in millimetres that prints; 0.8 by default.
  • --angle ANGLE is the steepest overhang, in degrees below the horizontal, that prints without support; 45 by default, and it must lie strictly between 0 and 90.
  • --json prints the same reports as one JSON document, numbers unrounded.
  • --timeout SECONDS, as everywhere.

Exits 0 when no entry has a warning, 1 when any has, and 2 when the file cannot be read, holds no entries, or an option is not a number it takes.

Worked, exits 0:

dxcad printability bracket.dxcprt
usage: dxcad printability [-h] [--material MATERIAL | --density DENSITY] [--min-wall MIN_WALL]
                          [--angle ANGLE] [--json] [--timeout SECONDS]
                          project
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • --material MATERIAL: the filament, one of PLA, PETG, ABS, ASA, TPU, mild steel, stainless 304, aluminium 5052, galvanised steel; PLA by default
  • --density DENSITY: the material's density in g/cm3, for a filament not in that list
  • --min-wall MIN_WALL: the thinnest wall in mm that prints; 0.8 by default
  • --angle ANGLE: the steepest overhang in degrees below the horizontal that prints; 45.0 by default
  • --json: print the same reports as one JSON document, numbers unrounded
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

bom

A bill of materials: parts a model put in with place() from one source, as one shape, are one line with a count, and every other part is a line of its own. Each line gives its name (the start its parts' names share, so bolt_1 to bolt_4 are bolt), how many, one part's volume, its mass when a material or a density is given, one part's size before it was placed, and the file it came from when it was placed from one or taken from another project with use() (item 576), as from bracket.dxcprt:bracket.

Takes what info takes. Writes nothing but its own output.

  • --material MATERIAL gives each line's mass in that filament, one of those printability takes.
  • --density DENSITY gives each line's mass at that density in g/cm3, instead of --material.
  • --csv prints the bill as CSV with a header row: name, count, volume, mass, size_x, size_y, size_z, the parts, joined by ;, and the source file.
  • --flat totals each part over the whole assembly. Without it an assembly holding sub-assemblies (use(path, as_group=True), item 577) is printed as a tree, each sub-assembly a line naming its file with its own bill set in under it, the counts multiplied down it.
  • --timeout SECONDS, as everywhere.

Exits 0, and 2 when the file cannot be read or holds no entries.

Worked, exits 0:

dxcad bom bracket.dxcprt --csv
usage: dxcad bom [-h]
                 [--material MATERIAL | --density DENSITY | --default-material DEFAULT_MATERIAL]
                 [--csv] [--columns KEYS] [--each] [--flat] [--timeout SECONDS]
                 project
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • --material MATERIAL: give each line's mass in this filament, one of PLA, PETG, ABS, ASA, TPU, mild steel, stainless 304, aluminium 5052, galvanised steel
  • --density DENSITY: give each line's mass at this density in g/cm3
  • --default-material DEFAULT_MATERIAL: take each part with no material of its own to be made of this, marked (default), as the window's Default material does
  • --csv: print the bill as CSV, with a header row
  • --columns KEYS: print the bill as CSV in a drawing's parts list columns, comma-separated, of item, part_number, description, material, qty, rev, size and mass
  • --each: list every part on a line of its own, rather than identical parts as one
  • --flat: total each part over the whole assembly rather than listing sub-assemblies as a tree
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

where-used

Lists the assemblies and drawings in a folder, and in every folder below it, that use a part file, each with how many copies it holds: the projects whose model uses the file through use() or puts it in with place(), read from each model without running it, and the drawings whose model is the file. A part keeps a stable id through renames, so an assembly using it by an old name still finds it.

Writes nothing but its own output.

Exits 0, or 2 for a part file or a folder that is not there.

Worked, exits 0:

dxcad where-used bracket.dxcprt .
usage: dxcad where-used [-h] path folder
  • path: the part file, a .dxcprt
  • folder: the folder to search, and every folder below it

interference

Whether any two parts clash: for every pair, in document order, overlap with the volume they share and its bounding box, touching when they meet but share no volume (a face against a face), or clear.

Takes what info takes. Writes nothing but its own output.

  • --name NAME checks only the pairs among the parts named, one --name each; every part by default.
  • --json prints the pairs as one JSON document, with how many overlap.
  • --timeout SECONDS, as everywhere.

Exits 0 when no pair overlaps, 1 when any does, and 2 when the file cannot be read or names no such part.

Worked, exits 0:

dxcad interference bracket.dxcprt
usage: dxcad interference [-h] [--name NAME] [--json] [--timeout SECONDS] project
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • --name NAME: check only the pairs among the parts named, one --name each; every part by default
  • --json: print the same pairs as one JSON document
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

render

A picture of the parts as a PNG, drawn by OCCT with no window on screen: the picture the agent door's render_view tool answers for the same request, byte for byte.

Takes what info takes and the .png file to write.

  • --name NAME draws only the parts named, one --name each; every part by default.
  • --view {front,back,left,right,top,bottom,isometric}; isometric by default.
  • --mode {shaded_edges,shaded,wireframe,translucent}, the window's display modes; shaded_edges by default.
  • --width WIDTH and --height HEIGHT in pixels, each 1 to 2048; 800 by 600 by default.
  • --explode FACTOR draws the parts moved apart, as export --explode writes them.
  • --timeout SECONDS, as everywhere.

Exits 0, 1 when this machine cannot draw, and 2 when the file cannot be read, names no such part or a size is out of range.

Not run by the test: drawing with no window is built for Windows only so far, and the page's commands are run on every platform the suite is.

usage: dxcad render [-h] [--name NAME] [--view {front,back,left,right,top,bottom,isometric}]
                    [--mode {shaded_edges,shaded,wireframe,translucent}] [--width WIDTH]
                    [--height HEIGHT] [--explode FACTOR] [--theme {light,dark}] [--timeout SECONDS]
                    project output
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • output: the .png file to write
  • --name NAME: draw only the parts named, one --name each; every part by default
  • --view {front,back,left,right,top,bottom,isometric}: where the parts are seen from; isometric by default
  • --mode {shaded_edges,shaded,wireframe,translucent}: how the parts are drawn, as the window's display modes; shaded_edges by default
  • --width WIDTH: pixels across; 800 by default
  • --height HEIGHT: pixels down; 600 by default
  • --explode FACTOR: draw the parts moved apart by FACTOR, as an exploded view; 0 by default
  • --theme {light,dark}: the view's background and part colours, as View > Theme; light by default
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

export

One entry, or all of them, written out for a slicer, a mesher or another CAD.

Takes a project and the file to write, which ends in .step, .stl, .3mf or .brep; with --all, a directory instead. Writes that file, or one file per entry in that directory.

A file ending .dxf or .svg is a drawing instead: the Sketches the model (or the project's model) names at its top level, one layer or group each, named as the model names them, in millimetres, with lines, arcs, circles, ellipses and splines each written as themselves. A model that makes only sketches, and registers no part, draws as well as any.

  • --name NAME is the entry to write; the first entry by default. For a drawing it is the one sketch to draw, every sketch by default.
  • --all writes every entry into the output directory, one file each, or with a drawing format every sketch, one file each.
  • --format {3mf,brep,dxf,step,stl,svg} is the format --all writes; step by default.
  • --explode FACTOR writes each part moved apart as an exploded view of the whole project shows it: away from the assembly's centre of mass along the line to the part's own, FACTOR times that distance; 0 is assembled. Not for a drawing.
  • --timeout SECONDS, as everywhere.

Exits 0, or 2 when the project cannot be read, the name is not there or the suffix names no format DX-CAD writes.

Worked, exits 0:

dxcad export bracket.dxcprt bracket.step
usage: dxcad export [-h] [--name NAME] [--all] [--format {3mf,brep,dxf,step,stl,svg}]
                    [--explode FACTOR] [--timeout SECONDS]
                    project output
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input
  • output: the file to write, ending in .step, .stl or .3mf, or .dxf or .svg for a drawing of the model's sketches; a directory with --all
  • --name NAME: the entry to write, the first by default; for a drawing, the one sketch to draw, every sketch by default
  • --all: write every entry into the output directory, one file each
  • --format {3mf,brep,dxf,step,stl,svg}: the format --all writes; step by default
  • --explode FACTOR: write each part moved apart as an exploded view of the whole project shows it, FACTOR times its distance from the centre; 0 is assembled
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

drawing

Given a .dxcdrg, a drawing saved from the window (items 572 and 682; an older .dxcaddrg too), it draws that drawing from its project as the project is now, with its own sheet, views, scale and fields, and writes what the window's Export Drawing writes; the file to write may follow it, dxcad drawing part.dxcdrg part.pdf. A project that is gone is named by its path, and exits 2.

Otherwise, a drawing sheet of a project's parts: the front, top, right and isometric views, visible edges solid and hidden ones dashed, at one standard scale that fits every view in its quarter of the drawing area, inside the title block, with the bill of materials as a parts list. The views are fitted first: a list longer than one column of the sheet takes a second column beside them only where they keep their scale, and runs on to further sheets, the same title block numbered on, where they would not. Written as a DXF (AutoCAD 2000, one layer per view's visible and hidden edges) and as a one-page PDF the size of the sheet. The title block states the scale and the sheet size and names the project, its file and the date. The front, top and right views carry their overall width and height, and every drilled hole a diameter callout where it is seen round, with its depth when it is blind, each a DIMENSION in the DXF; none is put over a view, and one that would be is stacked further out. This is a draft a person finishes, not a toleranced drawing.

Takes a project or a model.py. Writes PROJECT-drawing.dxf and PROJECT-drawing.pdf beside it, or the files named.

  • --output PATH is a file to write, ending .dxf or .pdf; give it twice for both.
  • --sheet NAME is the sheet: A4, A3, A2 or A1, landscape on the default title block, or one of ten ready sheets (item 571): ISO 5457 ISO-A4-portrait, ISO-A4, ISO-A3, ISO-A2, ISO-A1 and ISO-A0 with an ISO 7200 title block, and ASME Y14.1 ANSI-A, ANSI-B, ANSI-C and ANSI-D with an ANSI one, each with the Designmatix logo; on those the scale is the largest of 5:1, 2:1, 1:1, 1:2, 1:5, 1:10 and 1:20 that fits. A3 by default; any other name is refused, listing them. Their fields a person fills are company_name, drawn_by, checked_by, material, finish, tolerance, drawing_no and rev_number.
  • --font NAME letters the sheet in a TrueType font of the system's, by its file's name (arial) or a .ttf path: named in the DXF's STYLE table and embedded in the PDF. The bundled DejaVuSans by default; a named font this machine lacks is replaced by it, with a warning naming both.
  • --text-height MM is the height of the dimensions, the view labels and the title block's fields: 2.5, 3.5, 5 or 7.
  • --field NAME=VALUE fills a field the title block names, such as customer_name or project_name; it may be given again for another. Fields nobody fills are left empty.
  • --force writes over a file that is already there.
  • --timeout SECONDS, as everywhere.

Exits 0, 1 when the sheet cannot be made, or 2 when the project cannot be read, a file is in the way or a suffix is neither .dxf nor .pdf.

Worked, exits 0:

dxcad drawing bracket.dxcprt --sheet A4 --field customer_name=ACME
usage: dxcad drawing [-h] [--output PATH]
                     [--sheet {A4,A3,A2,A1,ISO-A4-portrait,ISO-A4,ISO-A3,ISO-A2,ISO-A1,ISO-A0,ANSI-A,ANSI-B,ANSI-C,ANSI-D}]
                     [--font NAME] [--text-height MM] [--field NAME=VALUE] [--force]
                     [--timeout SECONDS]
                     project [OUTPUT]
  • project: a .dxcprt or .dxcasm file, or a .py model to run, or - for a model on standard input, or a .dxcdrg drawing saved from the window
  • OUTPUT: a file to write, ending .dxf or .pdf, as --output names one
  • --output PATH: a file to write, ending .dxf or .pdf; may be given twice; by default PROJECT-drawing.dxf and PROJECT-drawing.pdf beside the project
  • --sheet {A4,A3,A2,A1,ISO-A4-portrait,ISO-A4,ISO-A3,ISO-A2,ISO-A1,ISO-A0,ANSI-A,ANSI-B,ANSI-C,ANSI-D}: the sheet: A4 to A1 landscape, or one of the ISO and ANSI sheets; A3 by default
  • --font NAME: a TrueType font of the system's, by its file's name such as arial, or a .ttf path, named in the DXF and embedded in the PDF; the bundled DejaVuSans by default
  • --text-height MM: the height of the dimensions, labels and title block fields: 2.5, 3.5, 5 or 7
  • --field NAME=VALUE: fill a field the title block names, such as customer_name=ACME; may be repeated
  • --force: write over an output file that is already there
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

flat

The flat pattern of a sheet part, as a DXF for a laser or a plasma table: the outline to cut on layer CUT, each round hole a circle on CUT, each rectangular cutout a closed polyline on CUT, each bend's two lines on layer BEND and a note beside each bend on layer NOTES, such as UP 90 R2. The project's model.py is re-run, as rebuild runs it, and the pattern is worked out from what the model built the part from: its base profile, its flanges, and the thickness, bend radius and K-factor of its SheetSpec. Prints the file written, then the flat's size and bend count, such as 124.524 x 50.000 mm, 1 bend, with its hole count after them when it has holes: 124.524 x 50.000 mm, 1 bend, 1 hole, and its cutout count last when it has cutouts, the base's and its flanges' together: 124.524 x 50.000 mm, 1 bend, 1 cutout.

Takes a project carrying a model.py. Writes NAME-flat.dxf beside it, or the file named.

  • --part NAME is the sheet part to unfold, one the model registers with part from base_flange and flange.
  • --output PATH is the .dxf file to write, or a .svg: an SVG in millimetres, +y up, with the outline and each cutout as a closed path, holes as circles, bend lines dashed and each bend's note as text; or a .step or .stp: the flat as one solid, the outline extruded by the sheet's thickness from z = 0 with every hole and cutout cut through it, for a CAM program that wants a solid. Any other name is written as DXF.
  • --all unfolds every sheet part the model registers instead, each to NAME-flat.dxf beside the project, in the model's order, printing one line for each: its path, then its size and bend count after a colon. It takes no --part and no --output.
  • --title writes the part's name and the sheet's thickness, such as tray, 2 mm, once below the flat on the DXF (a TEXT on layer NOTES) or the SVG (a text), so the cut part can be told apart on the shop floor. With --all, each part's own name. A .step or .stp output ignores it.
  • --bend-zones also draws the two edges of each bend zone, continuous, on layer BEND-ZONE (a class of its own in the SVG), beside the one dashed centre line on BEND that every flat has, for a shop that wants them. Without it every byte is as before.
  • --edges prints, straight after the size line, one line per edge of the part's outline, numbered from 0 as flange() takes them: its two ends, its length and the flange on it with its leg, or free, such as edge 1: (100, 0) to (100, 50), 50.000 mm, flange UP 90 R2 20.000 mm. With --all, each part's edge lines follow its own line. Without it the output is as above.
  • --bends prints a bend table for the press brake after the size line and any edge lines, one line per bend in the flat's order: its direction, angle and inside radius, its bend allowance worked with that radius, and the length of its bend lines, such as bend 1: UP 90 R2, allowance 4.524 mm, length 50.000 mm. With --all, each part's bend lines follow its own line. Without it the output is as above.
  • --cut prints, after the size line and any bend lines, the flat's cut length, the outline's perimeter plus every hole's circumference and every cutout's perimeter, and its area, the outline's less every hole and cutout, for quoting a laser or a plasma table, such as cut length 349.048 mm, area 6226.195 mm², then a line with the flat's mass, its area times the thickness at its sheet's metal, and the metal, such as mass 97.751 g, mild steel. With --all, each part's lines follow its own lines. Without it the output is as above.

A shop's CAM software may want a different DXF. --profile NAME writes it as a shop export profile has it: the DXF version (R12, R2000, R2013 or R2018), the units (mm or inch), the names of the cut, bend and notes layers, each bend as its dashed centre line or its two zone edges, holes as circles or as polylines within a chord tolerance, notes on or off, and a colour for each layer. Profiles are kept in DX-CAD's settings; Default is the plain output above, byte for byte, and is what is written without --profile. --profiles lists them, one line each. A profile applies to a DXF; an SVG or STEP is written as ever. An unknown profile is refused, listing the names.

Exits 0, or 2 when the project cannot be read or carries no model.py, the model fails, it builds no part of that name, the part is not a sheet part, neither --part nor --all is given, --all comes with --part or --output, or --all finds no sheet part. With --all, a sheet part that cannot be unfolded is said on stderr, the others are still written, and the exit is 1. The bracket is not a sheet part:

Worked, exits 2:

dxcad flat bracket.dxcprt --part bracket
usage: dxcad flat [-h] [--part PART] [--all] [--output OUTPUT] [--bends] [--cut] [--edges] [--title]
                  [--bend-zones] [--profile PROFILE] [--profiles]
                  [project]
  • project: a .dxcprt or .dxcasm file carrying a model.py (needed but for --profiles)
  • --part PART: the sheet part to unfold
  • --all: unfold every sheet part the model registers, each to NAME-flat.dxf (item 514)
  • --output OUTPUT: the .dxf file to write, or a .svg, or a .step or .stp for the flat as a solid; NAME-flat.dxf beside the project by default
  • --bends: after the size line, print one line per bend for the press brake (item 543)
  • --cut: after the size and any bend lines, print the cut length and area (item 549)
  • --edges: after the size line, print one line per outline edge and its flange (item 552)
  • --title: write the part's name and the thickness below the flat on the DXF or SVG (item 555)
  • --bend-zones: also draw each bend zone's two edges, continuous, on layer BEND-ZONE (item 565)
  • --profile PROFILE: write the DXF as the shop export profile of this name has it (item 607); Default is the plain output
  • --profiles: list the shop export profiles and exit (item 607)

merge

Two projects into one, the first project's entries followed by the second's. The model is not merged: the result carries no script, since no one script builds both halves.

Takes two projects and the file to write. Writes that project.

Exits 0, or 2 when either project cannot be read, when the two hold an entry of the same name, or when the output is a .py model.

Worked, exits 0:

dxcad examples flange
dxcad run flange.py --output flange.dxcprt
dxcad merge bracket.dxcprt flange.dxcprt both.dxcasm
usage: dxcad merge [-h] first second output
  • first: the project whose entries come first
  • second: the project whose entries are appended
  • output: the .dxcprt or .dxcasm file to write

import

A project made out of STEP or BREP files, one entry per file, each named after the file it came from.

Takes the project to write and the parts to read. Writes that project.

Exits 0, or 2 when a part cannot be read or the output is a .py model. A part that comes in as several solids is one entry still.

An output ending .dxcasm brings one STEP assembly in whole instead: the assembly as a .dxcasm, a .dxcprt for each distinct part with its shape beside it as a .brep of the same name, and a .dxcasm for each sub-assembly, used as a group, so the file's levels are kept. Each part keeps its name, colour, part number, revision and properties, and each component its place, in millimetres whatever unit the file was written in.

Worked, exits 0:

dxcad import imported.dxcprt bracket.step
usage: dxcad import [-h] output [parts ...]
  • output: the .dxcprt or .dxcasm file to write; a .dxcasm brings one STEP assembly in whole
  • parts: the .step or .brep files to read

convert

One file into another format without a project in between: STEP or BREP in, STEP, STL, 3MF or BREP out.

Takes the file to read and the file to write. Writes that file.

Exits 0, or 2 when the input cannot be read or either suffix names no format DX-CAD knows.

Worked, exits 0:

dxcad convert bracket.step bracket.stl
usage: dxcad convert [-h] input output
  • input: the .step or .brep file to read
  • output: the .step, .stl, .3mf or .brep file to write

run

A model.py into a project: the script is run, every part it registers becomes an entry, and the model travels inside the project it built. This is the command the parametric model is made of.

Takes the model to run, or - to read one from standard input. Writes the project and prints its name, then one line per part with its volume.

  • --output OUTPUT is the project to write; with none, the model's own name, a .dxcprt when it builds one part and a .dxcasm when it builds more or uses another file. Required with -.
  • --force writes over an output file that is already there.
  • --timeout SECONDS, as everywhere.

Exits 0, or 2 when the model raises, when the output is there already without --force, or when the output would be written over the model itself.

Worked, exits 0:

dxcad run bracket.py --output bracket.dxcprt --force
usage: dxcad run [-h] [--output OUTPUT] [--force] [--timeout SECONDS] model
  • model: the model.py to run, or - to read one from standard input
  • --output OUTPUT: the .dxcprt or .dxcasm file to write; with none, the model's own name, a .dxcprt for one part and a .dxcasm for more; required with -
  • --force: write over an output file that is already there
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

rebuild

The other half of run: re-run the model a project already carries and bring its shapes level with it. It says what changed, or nothing changed when the file already agrees with its model.

Takes a project that carries a model. Writes that project, or another.

  • --output OUTPUT is the file to write the result to; the project itself by default.
  • --dry-run says what would change and writes nothing.
  • --force writes over an output file that is already there.
  • --timeout SECONDS, as everywhere.

Exits 0, or 2 when the project carries no model, when the model raises or when the output is there already without --force.

Worked, exits 0:

dxcad rebuild bracket.dxcprt
usage: dxcad rebuild [-h] [--output OUTPUT] [--dry-run] [--force] [--timeout SECONDS] project
  • project: a .dxcprt or .dxcasm file carrying a model.py
  • --output OUTPUT: the file to write the result to; the project itself by default
  • --dry-run: say what would change and write nothing
  • --force: write over an output file that is already there
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

script

The model.py a project carries: printed, written out, replaced, or taught to read the parts it does not build.

Takes a project, or nothing with --template. Writes what the option asks for, and prints the script when none does.

  • --template gives the model.py a new project starts from rather than a project's own.
  • --output OUTPUT writes the script to this file instead of printing it.
  • --set SOURCE replaces the project's script with this file's text, or with standard input's for -.
  • --adopt [DIRECTORY] writes every part the model does not build to a file in that directory and adds the line that reads it back.
  • --force writes over an output file that is already there.
  • --timeout SECONDS, as everywhere.

Exits 0, or 2 when the project carries no model, when the output is there already without --force, or when the output would be written over a project.

Worked, exits 0:

dxcad script bracket.dxcprt --output bracket-model.py
usage: dxcad script [-h] [--template] [--output OUTPUT | --set SOURCE | --adopt [DIRECTORY]]
                    [--force] [--timeout SECONDS]
                    [project]
  • project: a .dxcprt or .dxcasm file; not needed with --template
  • --template: give the model.py a new project starts from, rather than a project's own
  • --output OUTPUT: write the script to this file instead of printing it
  • --set SOURCE: replace the project's script with this file's text, or with standard input's for -
  • --adopt [DIRECTORY]: write every part the model.py does not build to a file in this directory, the project's own name ending .parts by default, and add the line that reads it
  • --force: write over an output file that is already there
  • --timeout SECONDS: stop a model that runs longer than this; no limit by default

gui

The viewer: an OpenCASCADE scene in a Qt window, with the model in a pane beside it. Qt is imported here and nowhere else, so every other command runs on a machine with no display.

Takes a project or a model to open, or nothing for an empty document. Writes what the window is asked to save.

Exits 0 when the window closes, or 2 when the file given cannot be read.

Not run by the test: it opens a window and waits for a person. What the window holds is in gui.md, and whether it draws correctly is a manual check.

dxcad gui bracket.dxcprt
usage: dxcad gui [-h] [project]
  • project: the .dxcprt or .dxcasm file or the .py model to open

doctor

What is installed and whether it works: one line each for DX-CAD, Python, cadquery-ocp, PySide6, the platform and the plugins loaded (none, or each with its version, or why it was skipped; see plugins.md) and whether DX-CAD's files are associated (see associate below), and the folder DX-CAD's log is kept in (log, DX-CAD\logs under the local app data on Windows, where every dxcad command, each refusal and any error in full are written; nothing is sent anywhere), then the smoke test, which builds a part, checks it and exports it. The first thing to run when an install looks wrong, and the first thing to paste into a report.

Takes nothing. Writes nothing but its own output and a part in a temporary directory.

  • --gui builds the window after the smoke test, shows it, closes it and prints one line starting GUI OK, or GUI FAILED with the error. A windowed build has no console to fail on, so this is how to tell that its window starts. Whether the view draws the part correctly is still a check by eye.
  • --report prints the support report instead, everything a bug report needs (item 647): DX-CAD's version and commit, Python, OCCT and Qt, the OS, the OpenGL renderer, vendor and version, where the settings and the log are kept, the plugins and their state, the view's theme and the log's last 50 lines. Nothing personal goes in: your own folder is written as ~, and your login and the machine's name, where they would show, as <user> and <host>. Help > Copy Support Report in the window gives the same text.
  • --copy, with --report, puts the report on the clipboard as well, to paste into the bug report form.

Exits 0, or 1 when the smoke test fails or, with --gui, the window does not come up, or 2 for --copy without --report. A distribution that is missing is said to be not installed and is not on its own a failure.

Worked, exits 0:

dxcad doctor
usage: dxcad doctor [-h] [--gui] [--report] [--copy]
  • --gui: after the smoke test, build the window, show it and close it
  • --report: print the support report a bug report needs instead: versions, OpenGL, paths, plugins, theme and the log's last lines, with nothing personal in it
  • --copy: with --report, put the report on the clipboard too

examples

The example models that travel in the package, listed or copied out. Every one of them is in examples/README.md as well.

Takes the name of one example, or nothing to list them all. Writes the copy where it is told to.

  • --output FILE is the file to write the copy to; NAME.py in the working directory by default.
  • --all DIR copies every example into DIR, which is made if it is not there.
  • --force writes over an output file that is already there.

Exits 0, or 2 for an unknown name, for a file that is there already without --force, or for --all given a name as well.

Worked, exits 0:

dxcad examples
usage: dxcad examples [-h] [--output FILE] [--all DIR] [--force] [name]
  • name: the example to copy out; with none, every example is listed
  • --output FILE: the file to write the copy to; NAME.py in the working directory by default
  • --all DIR: copy every example into DIR, which is made if it is not there
  • --force: write over an output file that is already there

A model.py for the gallery, checked the way the test suite checks the shipped examples, one line each: its first line is the SPDX licence line, its docstring gives a title and known tags, it imports nothing, it builds at least one part within 60 seconds, every part is valid, and it builds again, valid, with its first number changed. Each line starts ok or FAIL. new starts a part for a contributor: a model.py of three numbers and a box, with a docstring to fill in, and its row in the examples' index in name order. The starter passes check as it is written.

Takes check and the path of the model.py, or new and the new part's name, which must be a Python identifier no example has yet.

  • --examples DIR is the folder new writes into; docs/examples, from the root of a checkout, by default.

Exits 0 when every line passes, 1 when one fails, or 2 for a file that is not there; new exits 0, or 2 for a name it refuses.

Worked, exits 0:

dxcad gallery check bracket.py
usage: dxcad gallery [-h] [--examples DIR] {check,new} TARGET
  • {check,new}: check: run the gallery's checks on TARGET, one line each; new: write a starter part called TARGET and its row in the examples' index
  • TARGET: the model.py to check, or the new part's name
  • --examples DIR: with new, the examples folder to write into; docs/examples by default

plugins

Which plugins are installed and what each one brings. The first line is plugin API N, the version a plugin's require() is checked against. Then each plugin gives its name, its version and the distribution it came from, and four indented lines list the model names, commands, tools and window actions it registered, none where it registered nothing. A plugin that was skipped gives its reason instead, such as needs plugin API 2, this DX-CAD has 1. With no plugin installed it prints no plugins. See plugins.md for how to write one.

Takes nothing. Writes nothing but its own output.

Exits 0.

Worked, exits 0:

dxcad plugins
usage: dxcad plugins [-h]

Takes no arguments.

addons

Installs, lists, disables, enables and removes add-ons, as Help > Add-ons does in the window. list prints one line per installed plugin: its name and version, its publisher, its licence state (open, unlocked, or locked and what it needs), whether it is enabled and the folder it lives in; no add-ons when there are none. install WHEEL checks a plugin wheel first: one that declares no dxcad.plugins entry point, is built for another platform or for another plugin API is refused with the reason. A plugin wheel says its API with the classifier Framework :: DX-CAD :: Plugin API :: N; one without it is taken as built for API 1. The wheel is installed into DX-CAD's own add-ons folder (DX-CAD\addons under the local app data on Windows, ~/Library/Application Support/DX-CAD/addons on macOS and ~/.local/share/DX-CAD/addons on Linux, or where DXCAD_ADDONS_DIR says), never into a Python of the user's and never inside the installed program, which a signed app, Program Files and an AppImage do not allow, and loads at the next start. disable NAME keeps a plugin installed but not loaded, enable NAME loads it again, and remove NAME uninstalls an add-on DX-CAD installed.

Writes only into the add-ons folder.

Exits 0, or 2 when a wheel is refused or there is no such add-on.

Worked, exits 0:

dxcad addons list
usage: dxcad addons [-h] {list,install,remove,enable,disable} [target]
  • {list,install,remove,enable,disable}: what to do
  • target: the wheel (.whl) to install, or the add-on's name

associate

Makes DX-CAD's files open in DX-CAD: older .dxcad projects with the DX icon, and on Windows the three document types too, each with an icon of its own: .dxcprt parts as DXCAD.Part, .dxcasm assemblies as DXCAD.Assembly, and .dxcdrg drawings, with older .dxcaddrg ones, as DXCAD.Drawing; for the current user alone and with no administrator rights: what an installer does, for a pip install, which has none. On Windows it writes the DXCAD.Project type the installer registers under HKEY_CURRENT_USER\Software\Classes, the icon from the package and dxcad-gui to open the file with, and asks Explorer to show it. On Linux it writes the desktop entry, the shared-mime-info file and the icon under $XDG_DATA_HOME (~/.local/share when unset) and rebuilds the user's MIME and desktop databases where the tools are there. On any other desktop, macOS among them, it says what it would do and does nothing. dxcad doctor says whether the association is in place.

  • --remove takes the association out again, every extension, leaving an extension's key alone when another program has since claimed it.

Exits 0, or 1 when the registry or the files cannot be written.

dxcad associate

Not run by the test: it writes into the user's own registry or desktop database, which a test run must leave as it found it; the suite registers under a key of its own instead.

usage: dxcad associate [-h] [--remove]
  • --remove: take the association out again

freeze

The PyInstaller spec a desktop build is made from, written for this machine's desktop or another's. Nothing is built and PyInstaller is never imported, so the spec can be written on a machine that does not have it.

Takes nothing. Writes dxcad.spec and prints it, then the PyInstaller command line to run over it.

  • --platform {windows,macos,linux} is the desktop to write the spec for; this machine's by default.
  • --output OUTPUT is the directory to write the spec into; the working directory by default.
  • --pack DIR zips DIR, the directory a freeze collected, into the output directory instead, and prints the zip's path. Everything goes in under one DX-CAD/ folder; the zip is named after the version and the platform, as DX-CAD-<version>-windows-x64.zip, and two packs of one build are the same bytes. With DXCAD_SIGN_THUMBPRINT set, a DIR whose executables are not signed yet is refused, naming the first, so a signed release's zip cannot ship them unsigned.
  • --appdir DIR lays DIR, the directory a Linux freeze collected, out as DX-CAD.AppDir in the output directory instead, and prints its path: DIR whole as usr/bin, an AppRun that starts DX-CAD, the desktop entry and the DX icon. appimagetool packs it into DX-CAD-x86_64.AppImage, as CI's build job does (item 643). An AppDir already there, or a DIR with no DX-CAD executable, is refused. The macOS spec's bundle carries Info.plist (bundle id uk.co.designmatix.dxcad, the version) and the .icns icon, and CI packs DX-CAD.app into DX-CAD-<version>-macos.dmg.
  • --installer DIR builds the Windows installer of DIR, the directory a freeze collected, into the output directory instead, with Inno Setup 6's ISCC found on PATH or in its default install folder, and prints its path, DX-CAD-<version>-windows-x64-setup.exe. Without Inno Setup it says so, naming it, and builds nothing. Windows only. The installer script is the one the package carries as dxcad/installer/dxcad.iss, so this works from a pip install, else a checkout's installer/dxcad.iss; it says which.
  • --sign, with --installer, signs the build with installer/sign.ps1 through PowerShell. The executables in DIR (DX-CAD.exe, dxcad.exe, and dxcad-gui.exe where there is one) are signed before Inno Setup packs them. Then Inno Setup signs the uninstaller and the installer with the same script as it builds them. The certificate is the one DXCAD_SIGN_THUMBPRINT names, and the timestamp server is DXCAD_SIGN_TIMESTAMP (http://ts.ssl.com by default). Without the script, the variable or PowerShell, it says why and builds the installer unsigned.
  • --release DIR makes the signed Windows release of DIR into the output directory, every step in order: signs the executables, builds the installer and has Inno Setup sign it, packs the zip, reads back every signature with installer/verify.ps1, and prints the installer's and the zip's paths and a table of files, statuses and signers. Without Inno Setup, the signing script or DXCAD_SIGN_THUMBPRINT it is refused, saying why. Not with --pack or --installer.

Exits 0, 1 when ISCC, the signing or a signature fails, when a release cannot be signed or built, or when --pack finds an unsigned executable, or 2 when a directory it is given is not there or --appdir refuses it, the installer or the release is asked for another platform, --sign is given without --installer, or --release with --pack or --installer.

The Windows zip is what a GitHub release carries for someone without Python: they download DX-CAD-<version>-windows-x64.zip, unzip it anywhere, run DX-CAD.exe from the DX-CAD folder, and run dxcad.exe doctor there to tell that it works.

Not run by the test: the Windows spec is frozen by the suite through the release checklist's freeze step instead, and the macOS and Linux builds are made on machines this suite never sees.

dxcad freeze --platform linux
usage: dxcad freeze [-h] [--platform {windows,macos,linux}] [--output OUTPUT] [--pack DIR]
                    [--appdir DIR] [--installer DIR] [--sign] [--release DIR]
  • --platform {windows,macos,linux}: the desktop to write the spec for; this machine's by default
  • --output OUTPUT: the directory to write the spec into; the working directory by default
  • --pack DIR: zip DIR, a frozen build's collected directory, into the output directory for a release, instead of writing the spec
  • --appdir DIR: lay DIR, a frozen Linux build's collected directory, out as DX-CAD.AppDir in the output directory for appimagetool, instead of writing the spec
  • --installer DIR: build the Windows installer of DIR, a frozen build's collected directory, into the output directory with Inno Setup, instead of writing the spec
  • --sign: with --installer, sign the executables, the uninstaller and the installer with installer/sign.ps1; skipped, saying why, without it or DXCAD_SIGN_THUMBPRINT
  • --release DIR: make the signed Windows release of DIR into the output directory: sign the executables, build and sign the installer, pack the zip, verify every signature and print a table of files and signers