WireViz/docs/agent-threads/notebook-api/001-notebook-api-handoff.md
Ryan Malloy 65af27e0da Add notebook-ready API: graph cache invalidation, structured BOM, fragment merging
Three additions to support interactive/notebook-style harness building:

- Graph cache invalidation: _invalidate_graph() called from all mutating
  methods so svg/png output reflects latest state after mutations
- bom_list_dicts(): JSON-serializable BOM export as list of dicts
- parse(harness=, populate_bom=): append YAML fragments to existing
  harness for cell-by-cell building with deferred BOM population

Templates persist on the Harness object across parse() calls so
component definitions in one fragment are available to connections
in later fragments.

Includes 24 new tests covering all three features plus full incremental
workflow simulation. All 122 tests pass.
2026-02-13 07:08:21 -07:00

3.9 KiB

Message 001

Field Value
From notebook-api-agent
To web-ui-agent
Date 2026-02-13T00:00:00Z
Re Notebook-Ready API additions to WireViz core

Three new capabilities have been added to the WireViz core library on testing/web-ui-features to support interactive/notebook-style harness building. All changes are backward-compatible.

1. Graph Cache Invalidation (automatic)

The Harness._graph cache is now invalidated automatically whenever any mutating method is called (add_connector, add_cable, add_additional_bom_item, add_mate_pin, add_mate_component, connect).

No action needed on your side. After any mutation, accessing harness.svg or harness.png will regenerate the diagram. Previously, calling .svg after adding new components would return stale output.

h.add_connector("X1", pins=[1, 2])
svg1 = h.svg  # renders X1

h.add_connector("X2", pins=[1, 2])
svg2 = h.svg  # automatically re-renders, now includes X2

2. Structured BOM Export via bom_list_dicts()

New function in wireviz.wv_bom:

from wireviz.wv_bom import bom_list_dicts

dicts = bom_list_dicts(harness.bom)
# Returns: [{"#": 1, "Qty": 2, "Description": "...", ...}, ...]
  • Returns List[Dict] (JSON-serializable)
  • Each dict maps column header to cell value
  • Empty BOM returns []
  • Safe for json.dumps(dicts, default=str)
  • Keys vary based on which columns have data (empty columns like P/N are omitted, matching bom_list() behavior)

3. YAML Fragment Merging via parse(harness=...)

The parse() function now accepts two new optional parameters:

from wireviz.wireviz import parse

parse(
    fragment,              # YAML string, dict, or file path
    return_types="harness",
    harness=existing_harness,  # append to this harness
    populate_bom=False,        # skip BOM for intermediate fragments
)

Cell-by-cell building pattern:

from wireviz.wv_harness import Harness
from wireviz.wv_dataclasses import Metadata, Options, Tweak
from wireviz.wireviz import parse
from wireviz.wv_bom import bom_list_dicts

# Create empty harness
h = Harness(metadata=Metadata({}), options=Options(), tweak=Tweak())

# Cell 1: Define connectors
parse({"connectors": {"X1": {"pins": [1,2]}, "X2": {"pins": [1,2]}}},
      return_types="harness", harness=h, populate_bom=False)

# Cell 2: Define cable
parse({"cables": {"W1": {"wirecount": 2, "colors": ["BK", "RD"]}}},
      return_types="harness", harness=h, populate_bom=False)

# Cell 3: Connect and render
parse({"connections": [[{"X1": [1,2]}, {"W1": [1,2]}, {"X2": [1,2]}]]},
      return_types="harness", harness=h, populate_bom=True)

# Now get outputs
svg_data = h.svg                    # rendered diagram
bom_data = bom_list_dicts(h.bom)    # JSON-serializable BOM

Mixed programmatic + YAML pattern:

h = Harness(metadata=Metadata({}), options=Options(), tweak=Tweak())
h.add_connector("X1", pins=[1, 2])  # programmatic

# YAML fragment references existing X1
parse({"connectors": {"X2": {"pins": [1,2]}},
       "cables": {"W1": {"wirecount": 2, "colors": ["BK","RD"]}},
       "connections": [[{"X1": [1,2]}, {"W1": [1,2]}, {"X2": [1,2]}]]},
      return_types="harness", harness=h, populate_bom=True)

Key behaviors:

  • When harness is provided, the fragment's metadata/options/tweak sections are ignored
  • Templates defined in earlier fragments are available to later fragments (persisted on the harness)
  • populate_bom=False skips BOM computation; call h.populate_bom() explicitly when ready
  • Existing components can be re-referenced across fragments without re-definition

Next steps for recipient:

  • Integrate harness.svg for live preview in notebook cells
  • Use bom_list_dicts() for the BOM panel/table
  • Implement cell-by-cell YAML parsing using parse(harness=h, populate_bom=False)
  • Call populate_bom=True on final render or when BOM display is requested