← Documentation index

BREADBOARD_CONFIG

NAME
DESCRIPTION
PHYSICAL MODEL
SECTIONS
MULTI-BOARD ASSEMBLIES
DEFAULTS AND THE ABSENT-SECTION SUBTLETY
RESOLUTION
EXAMPLES
SEE ALSO
AUTHOR
COPYRIGHT

NAME

breadboard_config - file format describing a real breadboard assembly’s own geometry

DESCRIPTION

A breadboard config file is a real Unix-style INI file: bracketed [section] headers, one key = value pair per line within each section, # starting a comment (to end of line). It describes exactly one real, physical breadboard assembly — how many sectors it has, each sector’s own real column/row geometry, which of the assembly’s own real rails exist and how they’re laid out — the "necessary and sufficient configuration" a consuming program needs to lay a real circuit out correctly on this specific board, not an idealized or averaged one.

Read and written by breadboard_config.py(1) (this project’s own Python module of the same name, and its own command-line front end); consumed throughout this project’s own placement and rendering pipeline — auto_layout.py(1) and render.py(1) both accept a config file (directly, or via the resolution strategy described under RESOLUTION below) and lay a real circuit out according to its own real geometry.

PHYSICAL MODEL

A real, multi-sector breadboard’s own real vertical structure, top to bottom, is: rail, sector, rail, sector, ..., rail, sector, rail. For N real sectors there are exactly N+1 real horizontal rails — ONE real rail before the first sector, ONE real rail SHARED between each pair of adjacent sectors (not two separate ones sitting side by side), and ONE real rail after the last sector. Every sector shares the SAME real shape (a real breadboard is assembled from identical units, not mixed ones); every one of the assembly’s own N+1 horizontal rails shares the SAME real template too.

Independently of these horizontal rails, the assembly may also have a real LEFT and/or RIGHT vertical rail running the assembly’s own full height — either edge, both, or neither, is a real possibility on a real board; a real vertical rail’s own primary role is feeding the horizontal rails with common power distribution, not connecting directly to individual components (see to_rail() in breadboard_lib.py for the real, corrected priority this drives).

SECTIONS

[board]

name

A quoted, human-readable label for this specific board (e.g. "3-sector board (breadboard1.png)"). Free text, for a human reading the file or a tool’s own diagnostic output — not otherwise interpreted.

sectors

How many real, stacked sector units this board has. A real, positive integer; 1 (a single sector, no internal rail) is a real, valid, common case, not just a placeholder.

pitch_mm

The real hole pitch, in millimetres. 2.54 (0.1", the de facto universal breadboard convention, confirmed against independent real sources) is the default — override only for a genuinely non-standard board.

sectors_per_board

How many of this board’s own real sectors physically fit on ONE physical board before a NEW board is needed — a practical rule of thumb: add a new physical breadboard once reasonable limits are exceeded, since no real breadboard has more than 4 sectors in practice. 0 (the default) means no real limit at all: every one of this board’s own sectors renders as ONE, single, physically continuous board — today’s existing, single-board behaviour, unchanged. A positive value genuinely GROUPS this config’s own real sectors into several, separate, physical boards of that many sectors each (the last one possibly shorter); see MULTI-BOARD ASSEMBLIES below for the full real account, including how this differs from, and combines with, the separate [multiboard] file format.

[sector]

The real geometry shared by EVERY sector on this board (see PHYSICAL MODEL above for why one real, shared shape is the correct model, not a per-sector override).
columns

How many real columns each sector has.

rows_per_half

How many real, connected holes make up one real half-column strip (the real span from the trench to a sector’s own outer edge, on either side). A common real measurement for this kind of breadboard: 5.

[rail]

The real, SHARED template for every one of the assembly’s own N+1 real horizontal rails (see PHYSICAL MODEL above) — not a per-sector or per-position concept; every horizontal rail on a real, uniformly-assembled board looks the same.
present

Whether this board genuinely has horizontal rails at all (a real, boolean field). See DEFAULTS AND THE ABSENT-SECTION SUBTLETY below for a real, important distinction between omitting this whole section and including it without setting present.

continuous

Whether a real rail is electrically continuous along its own full real length, as opposed to segmented (broken into isolated real runs partway along — a real, known variation on some boards, not yet further parameterized here: where the break lies is not modelled; see FutureResearch.org for the real, open item this leaves). Since 0.72.43 the build instructions read this flag: a board with continuous = false is stated, in the instructions’ header, as having split rails.

groups

How many real, physical clusters this rail’s own holes are grouped into. Real breadboards commonly break a rail’s own long run of holes into small, evenly-spaced clusters (a real, physical hole-layout detail, independent of continuous, which describes electrical continuity, not hole spacing). 0 means "not specified," not a claim of zero real groups.

group_size

How many real holes make up one such group. 0 means "not specified."

[rail.left] / [rail.right]

Each takes the SAME four real keys as [rail] above ( present, continuous, groups, group_size), describing the assembly’s own optional real left and/or right vertical rail independently (see PHYSICAL MODEL above). Either, both, or neither section may be present in a real file; a real board with no vertical rail at all simply omits both.

[geometry]

Pixel-level rendering constants, for render.py(1)’s own SVG output — real, but purely a drawing-scale concern, not a statement about the real, physical board itself.
col_spacing_px
row_spacing_px
trench_gap_px

Pixel spacing between adjacent real columns, adjacent real rows within a half, and the real trench’s own width, respectively. Default to this project’s own existing, established rendering values; override only if a specific real board’s own drawing needs to differ.

MULTI-BOARD ASSEMBLIES

A real circuit can outgrow ONE physical breadboard. This format offers TWO real, complementary mechanisms for that — they answer different real questions, and can be combined.

The FIRST, simpler mechanism is sectors_per_board (see [board] above): a single, real board config’s own real sectors are grouped into several, separate, physical boards of that many sectors each, purely as a real, uniform LIMIT — every board in the group still shares the exact same real [sector] and [rail] geometry, since they all come from the SAME [board] section. This is the right tool when every physical board in the assembly is genuinely identical, and the only real question is "how many sectors fit on one board before starting a new one."

The SECOND mechanism, a separate [multiboard] file, is for when the real boards themselves DIFFER — different real sector counts, different real column/row geometry, different real rails present. Several boards can be used together, each with its own structure described the same way a single board is, each board’s own real structure potentially its own.
[multiboard]

name

A quoted, human-readable label for the whole real assembly (free text, same convention as [board] ’s own name).

boards

A comma-separated list of real board config file paths, one per physical board in the assembly, in real, physical order. Each path is a real, complete, ordinary single-board config file (everything under SECTIONS above), read via the SAME real parser — a [multiboard] file adds nothing new to how ONE board’s own file is read, only how SEVERAL of them are found and combined. Relative paths are resolved against the [multiboard] file’s own real directory, not the current working directory.

A [multiboard] file’s own individual boards MAY also set their own real sectors_per_board — the two mechanisms are not mutually exclusive: an explicit, multi-board ecosystem can still have ONE of its own boards split further under escalation, if that specific board’s own circuit portion needs more sectors than physically fit on it.

DEFAULTS AND THE ABSENT-SECTION SUBTLETY

Every key in every section is optional; an omitted key takes the real, built-in default for that field (see each key’s own entry above, and breadboard_config.py(1)’s own --resolve-for output, or a bare invocation with no CONFIG_FILE argument, for the tool’s own complete, printed default configuration).

For the four [rail]-style sections specifically, there is a real, important distinction between omitting the WHOLE section and including an EMPTY one:

•

If a [rail]-style section is absent from the file entirely, the rail takes the value it has on the tool’s own default board (the board used when no config file is given at all, as a bare ppbreadboard_config prints it): the horizontal rails of [rail] are PRESENT, the left and right rails of [rail.left] and [rail.right] are ABSENT. A config file that describes a board WITHOUT horizontal rails must therefore say so, with [rail] and present = false. (Before 0.72.89 an absent [rail] meant no horizontal rails, which this manual then called the tool’s own default for a board with no config file at all; the tool’s default board has always had them.)

•

If a [rail]-style section is present in the file but does not itself set present, it defaults to true within that section — a real file that writes an (otherwise empty) [rail.left] section is declaring that a left rail genuinely exists, even without an explicit "present = true" line.

This is a real, deliberate asymmetry, not an inconsistency: WRITING a section at all is itself the real, meaningful signal that a rail of that kind exists on the real board being described; the keys within it refine what it looks like, not whether it’s there.

RESOLUTION

Neither auto_layout.py(1) nor render.py(1) requires an explicit config file for every real invocation. breadboard_config.py ’s own resolve_config_path() function (used by both) looks for one in a real, fixed priority order: an explicit path (e.g. render.py’s own --config flag), then the $PACKPAY_BREADBOARD_CONFIG environment variable (if set AND it names a real, existing file), then a file named breadboard.conf next to the schematic being processed, then the same filename in the current directory. If none of these resolve to a real, existing file, the tool’s own built-in default configuration (a single sector, no rails at all — see DEFAULTS above) is used instead, unless render.py’s own --require-config flag is given, in which case this is a real, hard error rather than a silent fallback.

Separately, auto_layout.py(1)’s own compute_optimal_config() can ESCALATE a given (or default) config’s own real sectors count, trying progressively more sectors of the SAME real shape until a real circuit fits or a real, configurable ceiling is reached — see render.py(1)’s own --use-computed flag. This never changes any OTHER real field in the config (sector geometry, rail presence, pitch) — only how many of the SAME real sector are stacked.

EXAMPLES

See breadboard1.conf and breadboard2.conf (this project’s own root directory) for two complete, real worked examples of the single-board format — two genuinely different physical boards, both round-trip tested against this format’s own real parser and writer. A minimal, single-sector file with a left rail:

[board]
name = "my board"
sectors = 1

[sector]
columns = 63
rows_per_half = 5

[rail]
present = true

[rail.left]
present = true
groups = 10
group_size = 4

A complete, real [multiboard] example follows, combining two GENUINELY DIFFERENT physical boards — not merely two different real sectors counts (that case is sectors_per_board’s own job, above, not [multiboard]’s): a small, single-sector board with no vertical rail at all, and a larger, two-sector board WITH a real left rail — three real files together, matching how a real user would lay them out on disk (the small board’s own file, the large board’s own file, and the assembly file naming both).

small_board.conf :

[board]
name = "small utility board"
sectors = 1

[sector]
columns = 30
rows_per_half = 5

[rail]
present = true

large_board.conf :

[board]
name = "large main board"
sectors = 2

[sector]
columns = 65
rows_per_half = 5

[rail]
present = true
continuous = true
groups = 10
group_size = 4

[rail.left]
present = true
continuous = true
groups = 10
group_size = 4

assembly.conf (the real [multiboard] file itself, naming both of the above by relative path):

[multiboard]
name = "two-board project: small utility + large main"
boards = small_board.conf, large_board.conf

Loading assembly.conf via load_multiboard_config() resolves boards against assembly.conf’s own real directory, then parses each real board file listed via the SAME load_config() every single-board file already uses — the result is a real MultiboardConfig with two real BoardConfig entries, the first with no vertical rail and 30 real columns per sector, the second with a real left rail and 65 real columns per sector, exactly as written.

SEE ALSO

breadboard_config.py(1), auto_layout.py(1), render.py(1), FutureResearch.org in packpay’s own documentation set (see Index.org).

AUTHOR

Péter Felecan <pfelecan@gmail.com>, with development assistance from Claude (Anthropic).

COPYRIGHT

Copyright © 2026 Péter Felecan. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.