Customize your own Graph
One can easily customize their own Graph by creating a new package and defining their own Tasks, Sockets, Properties, Executors and Serializers. Additionally, one can also provide the method to run the graph using their own executors and database.
Package structure
Your package should follow the following structure similar to this:
<your_package_name>/
├── __init__.py
├── tasks/
│ ├── __init__.py
│ ├── test.py
│ ├── ...
├── properties/
│ ├── __init__.py
│ ├── test.py
│ ├── ...
├── serializers/
│ ├── __init__.py
│ ├── test.py
│ ├── ...
├── sockets/
│ ├── __init__.py
│ ├── test.py
│ ├── ...
Define your new Task, Socket and Property in the folders tasks, sockets and properties respectively. Define your executor, serialization methods in the folders executors and serialization. For example, in the tasks.test.py file, define your test Task class.
Serialization adapters
Serialization is mounted per-graph via Graph(serialization=...). The adapter
is responsible for validating and serializing values for persistence, while the
core graph remains framework-agnostic.
For per-socket control, override serialization on the socket itself:
def serialize_special(self, store: bool = False):
return {"special": self._value}
task.inputs["x"].set_serializer(serialize_special)
When Task.to_dict(should_serialize=True) is called, inputs are collected
through sockets, so socket-level serialization runs before the adapter fallback.
Entry point
In the pyproject.toml file of your packages, you should define the entry points for your tasks, sockets and properties. For example, if your package name is abc, you should define the entry points like this:
[project.entry-points."abc.task"]
"abc.add" = "abc.tasks.test:Add"
"abc.multiply" = "abc.tasks.test:Multiply"
[project.entry-points."abc.property"]
"abc.any" = "abc.properties.test:SocketAny"
"abc.int" = "abc.properties.test:SocketInt"
[project.entry-points."abc.socket"]
"abc.any" = "abc.sockets.test:SocketAny"
"abc.int" = "abc.sockets.test:SocketInt"
Type mapping for annotations
When you use Python type annotations on task inputs/outputs, node-graph maps
the annotated types to socket identifiers. If a type is not in the mapping,
it falls back to the generic node_graph.annotated socket and records the
Python type in socket metadata (extras["py_type"]). This keeps links type-safe
without requiring custom socket classes for every domain type.
You can extend the mapping via an entry point:
[project.entry-points."node_graph.type_mapping"]
"abc.type_mapping" = "abc.mapping:type_mapping"
# abc/mapping.py
from some_pkg import CustomType
type_mapping = {
CustomType: "abc.custom_type",
}
Installation
Install your package locally:
pip instal -e .
or publish your package to pypi, and install it using pip.