"""Emit a minimal ``.kicad_pro`` so a sibling ``.kicad_sch`` + ``.kicad_pcb`` pair opens as one project in the KiCad GUI (double-click). KiCad pairs files by basename: a directory containing ``EchoEar-CoreBoard.kicad_pro`` + ``EchoEar-CoreBoard.kicad_sch`` + ``EchoEar-CoreBoard.kicad_pcb`` is treated as one project, and opening the .kicad_pro launches both editors with cross-navigation working. Without this file each .kicad_sch / .kicad_pcb opens as a one-off and KiCad puts up a "create project file?" dialog every time. The .kicad_pro is JSON. KiCad will fill in defaults for anything missing the next time the GUI opens it; we only emit the keys that meaningfully identify the project (``meta``, ``sheets`` for hierarchy root binding, empty stubs for ``board`` / ``schematic`` / ``net_settings`` so the top-level keys exist in the form KiCad expects). """ from __future__ import annotations import json def write_kicad_pro( project_basename: str, *, root_sheet_uuid: str | None = None, ) -> str: """Render a JSON .kicad_pro string for one project. ``project_basename`` is the filename without extension — e.g. ``"EchoEar-CoreBoard"``. ``root_sheet_uuid`` is the uuid at the top of the sibling .kicad_sch's ``(uuid ...)`` form; KiCad uses it to bind the root sheet to the project's hierarchy. If omitted, KiCad generates one on first open (works but causes a "save changes?" prompt the first time). """ sheets: list = [] if root_sheet_uuid: sheets.append([root_sheet_uuid, ""]) pro: dict = { "board": { "design_settings": { "defaults": {}, "rules": {}, }, "layer_presets": [], "viewports": [], }, "boards": [], "cvpcb": {"equivalence_files": []}, "erc": { "erc_exclusions": [], "meta": {"version": 0}, "pin_map": [], "rule_severities": {}, "rule_severitieslegacy": {}, }, "libraries": {"pinned_footprint_libs": [], "pinned_symbol_libs": []}, "meta": { "filename": f"{project_basename}.kicad_pro", "version": 1, }, "net_settings": { "classes": [], "meta": {"version": 3}, "net_colors": None, "netclass_assignments": None, "netclass_patterns": [], }, "pcbnew": { "last_paths": {}, "page_layout_descr_file": "", }, "schematic": { "annotate_start_num": 0, "bom_export_filename": "", "bom_fmt_presets": [], "bom_fmt_settings": {}, "bom_presets": [], "bom_settings": {}, "drawing": {}, "legacy_lib_dir": "", "legacy_lib_list": [], "meta": {"version": 1}, "net_format_name": "", "page_layout_descr_file": "", "plot_directory": "", "spice_external_command": "spice \"%I\"", "subpart_first_id": 65, "subpart_id_separator": 0, }, "sheets": sheets, "text_variables": {}, } return json.dumps(pro, indent=2)