atopile / fabll
Install for your project team
Run this command in your project directory to install the skill for your entire team:
mkdir -p .claude/skills/fabll && curl -L -o skill.zip "https://fastmcp.me/Skills/Download/3009" && unzip -o skill.zip -d .claude/skills/fabll && rm skill.zip
Project Skills
This skill will be saved in .claude/skills/fabll/ and checked into git. All team members will have access to it automatically.
Important: Please verify the skill by reviewing its instructions before using it.
How FabLL (faebryk.core.node) maps Python node/trait declarations into the TypeGraph + instance graph, including field/trait invariants and instantiation patterns.
0 views
0 installs
Skill Content
---
name: fabll
description: "How FabLL (faebryk.core.node) maps Python node/trait declarations into the TypeGraph + instance graph, including field/trait invariants and instantiation patterns. Use when defining new components or traits, working with the Node API, or understanding type registration."
---
# FabLL (Fabric Low Level) Module
`fabll` (primarily `src/faebryk/core/node.py`) is the high-level Python API for defining and working with hardware components. It bridges the gap between Python classes and the underlying `TypeGraph` and instance graph.
## Quick Start
```python
import faebryk.core.faebrykpy as fbrk
import faebryk.core.graph as graph
import faebryk.core.node as fabll
g = graph.GraphView.create()
tg = fbrk.TypeGraph.create(g=g)
class _App(fabll.Node):
pass
app = _App.bind_typegraph(tg=tg).create_instance(g=g)
```
## Relevant Files
- `src/faebryk/core/node.py` (Node/Traits/fields, type registration, binding/instantiation helpers)
- `src/faebryk/core/faebrykpy.py` (edge types used by FabLL under the hood)
- `src/faebryk/core/graph.py` (GraphView wrapper used by instances)
## Dependants (Call Sites)
- **Library (`src/faebryk/library/`)**: Every component (Resistor, Capacitor, etc.) inherits from `Node`.
- **Compiler**: Generates `Node` subclasses dynamically from `ato` files.
- **Solvers**: Operate on `Node` instances to extract parameters and constraints.
## How to Work With / Develop / Test
### Core Concepts
- **Nodes are wrappers over graph instances**: a `fabll.Node` is constructed with a `graph.BoundNode`.
- **Declaration via class attributes**:
- structural children: `SomeType.MakeChild(...)`
- trait attachments: `Traits.MakeEdge(SomeTrait.MakeChild().put_on_type())` (or similar)
- **Binding**:
- type binding: `MyType.bind_typegraph(tg)`
- instance creation: `.create_instance(g)`
- **Type identifiers**:
- library types (`faebryk.library.*`) intentionally have short identifiers (class name) for ato imports
- non-library types include a module-derived suffix; type IDs must be unique (enforced in `Node._register_type`)
### Development Workflow
1) Prefer adding behavior as a Trait rather than deepening class hierarchies.
2) If you need a new structural relation/field kind, it lives in `src/faebryk/core/node.py` (field system).
3) Keep an eye on invariants enforced at class creation time (metaclass + `__init_subclass__`).
### Testing
- Core tests: `ato dev test --llm test/core/test_node.py -q` and `ato dev test --llm test/library/test_traits.py -q`
## Best Practices
- **Prefer Traits**: Don't add methods to `Node` subclasses if they can be a Trait. This allows them to be applied to different component families.
- **Avoid deep inheritance**: FabLL enforces single-level subclassing for node types (`Node.__init_subclass__`).
- **Type-safe traversal**: when you must traverse trait edges manually, prefer `EdgeTrait.traverse(trait_type=...)`.
## Internals & Runtime Behavior
### Instantiation & Lifecycle
- **Don’t call `MyNode()` with no args**: instances are created from a bound type via `bind_typegraph(...).create_instance(...)`.
- **TypeGraph context is required**:
```python
import faebryk.core.graph as graph
import faebryk.core.faebrykpy as fbrk
g = graph.GraphView.create()
tg = fbrk.TypeGraph.create(g=g)
inst = MyNode.bind_typegraph(tg).create_instance(g=g)
```
- **Single-level subclassing invariant**: `Node.__init_subclass__` forbids “deeper than one level” inheritance for node types.
### Trait Implementation
- **Traits are Nodes**: Traits are not just Python mixins; they are `Node` subclasses that typically contain an `ImplementsTrait` edge.
- **Trait Definition**:
```python
class MyTrait(Node):
is_trait = Traits.MakeEdge(ImplementsTrait.MakeChild().put_on_type())
```
- **Resolution**: Use `node_instance.get_trait(TraitType)` to retrieve a trait instance. This performs a graph traversal.
### Performance & Memory
- **Type Creation**: Creating a type involves significant overhead (executing fields, resolving dependencies). Once created, instantiating instances is faster but still involves allocation in the Zig backend.
- **Tree Structure**: Nodes are linked via `EdgeComposition`. `add_child` creates this edge. Large trees (10k+ nodes) should be constructed carefully to avoid Python loop overhead; the underlying graph is efficient, but Python interactions cost time.