How the Zig-backed instance graph works (GraphView/NodeReference/EdgeReference), the real Python API surface, and the invariants around allocation, attributes, and cleanup. Use when working with low-level graph APIs, memory management, or building systems that traverse the instance graph.
cd ~/.claude/skills
git clone https://github.com/atopile/atopile.git atopile mkdir -p ~/.claude/skills/graph
curl -fsSL https://raw.githubusercontent.com/atopile/atopile/HEAD/.claude/skills/graph/SKILL.md \
-o ~/.claude/skills/graph/SKILL.md The faebryk.core.graph module is a thin Python wrapper around the Zig graph implementation.
Source-of-truth for behavior is:
src/faebryk/core/zig/src/graph/graph.zigsrc/faebryk/core/zig/src/python/graph/graph_py.zigsrc/faebryk/core/zig/gen/graph/graph.pyifrom faebryk.core.graph import GraphView
g = GraphView.create()
try:
_ = g.create_and_insert_node()
finally:
g.destroy()
src/faebryk/core/graph.pysrc/faebryk/core/zig/src/graph/graph.zigsrc/faebryk/core/zig/src/python/graph/graph_py.zigsrc/faebryk/core/zig/gen/graph/graph.pyisrc/faebryk/core/node.py (FabLL: nodes/traits are graph-backed)src/atopile/compiler/gentypegraph.py (compiler constructs typegraphs/instances via graph APIs)src/faebryk/core/graph_render.py (graph visualization)NodeReference / EdgeReference: value-like handles (UUIDs) into global backing storage in Zig.GraphView: a membership + adjacency view over those references (per-view arena + maps + bitsets).BoundNode / BoundEdge: “reference + owning GraphView pointer” wrappers used for traversal helpers.GraphView(), NodeReference(), EdgeReference() are not meant to be called; use the exposed factory methods.
GraphView.create()NodeReference.create(**attrs)EdgeReference.create(source=..., target=..., edge_type=..., **attrs)GraphView.create() allocates a Zig-side graph on the C allocator; it is freed only by GraphView.destroy().
u8 in Zig; treat them as 0..255 in Python (hashing/modulo happens on the Zig side).GraphView.init inserts a self_node; counts include it.src/faebryk/core/zig/gen/graph/graph.pyi)from faebryk.core.graph import GraphView, Node, Edge
g = GraphView.create()
try:
n1 = g.create_and_insert_node() # -> BoundNode
n2 = Node.create(name="n2") # -> NodeReference (not inserted yet)
bn2 = g.insert_node(node=n2) # -> BoundNode
e = Edge.create(source=n1.node(), target=bn2.node(), edge_type=7, name="link")
_be = g.insert_edge(edge=e) # -> BoundEdge
finally:
g.destroy()
GraphView.__repr__() prints GraphView(id=..., |V|=..., |E|=...) from Zig.python -m faebryk.core.graph (runs test_graph_garbage_collection).src/faebryk/core/zig/src/graph/*.ato dev compile (imports faebryk.core.zig, which compiles in editable installs).src/faebryk/core/zig/src/python/graph/graph_py.zig and ensure stubs regenerate.Key test entrypoints:
python -m faebryk.core.graphzig test src/faebryk/core/zig/src/graph/graph.zigYou MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation.
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Use when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation
Use when completing tasks, implementing major features, or before merging to verify work meets requirements
Use when starting feature work that needs isolation from current workspace or before executing implementation plans - ensures an isolated workspace exists via native tools or git worktree fallback
Use when starting any conversation - establishes how to find and use skills, requiring skill invocation before ANY response including clarifying questions