Create a design document and build according to it. Both are part of the same bundle — the former is drawing paper, while the latter is filling that paper with values.
The design document specifies which nodes have which attributes and how they connect to each other. It is the paper drawn in the web Ontology Schema Editor. When writing a skill in an IDE, there is no screen, so you create it here and verify later on the web.
When the owner describes the workflow in natural language, this is where it gets turned into a design document. The SDK fills in coordinates, colors, and internal identifiers—just write the meaning.
Creates a new design document and returns its twin_id. You may omit nodes and edges; they can be added later one by one.
Zio.ontology.list()
List of design documents: {twin_id, title, status, node_count, edge_count}.
↓ The following are for working with a single design document — the prefix Zio.ontology(twin_id) appears before the dot. They are not called directly as Zio.ontology. like list() or create(). See the “Build Design Document” section below for how to use them.
Zio.ontology(twin_id).info()
Reads the entire design document: {twin_id, title, nodes[], edges[], warnings[]}.
.update(title, description, status)
Updates the name label of the design document.
.drop()
Deletes the design document. Existing Neo4j nodes are untouched—the design document is just a reference sheet; even if there are hundreds of thousands of nodes, you can still delete the sheet.
Adds a node. display_property is the name shown inside the graph circle and takes one property name. Names starting with _ refer to nodes in another twin; they are created with only the primary key (PK)—see the box below.
Updates a node’s label. You cannot change name—changing it does not affect already‑created nodes with that label (the design document is not retroactive). Calling rename_node throws an AttributeError explaining why and how to proceed. If you only need the name to look different, update title; if you truly need a new node, create one, delete the old one, and decide what to do with the old label’s nodes yourself.
.drop_node(name)
Deletes a node. All connected edges are also removed, and the number of deleted edges is returned. Leaving orphaned edges causes broken visuals on the web interface.
Adds a property field. Read the two boxes below to understand unique and source.
.update_property(node, name, ...)
Updates only the specified fields; the rest remain unchanged.
.drop_property(node, name)
Removes a property. If it was the display_property, that slot is cleared as well—edges pointing to the removed property appear as empty circles in the graph.
Connects two nodes. rel is the actual Neo4j relationship name; e.g., add_edge("Worklog", "Author", "WRITTEN_BY") creates (Worklog)-[:WRITTEN_BY]->(Author). label is only for display. source_key and target_key specify which properties to join on (can be a list if multiple).
.drop_edge(source, target, rel=None)
If rel is omitted, all edges between the two nodes are removed.
Underscore (_) — Shortcut for Referencing Nodes in Other Twins
When you need to connect to an existing node inside another twin (e.g., shared Author or Project), do not redefine it here; instead prefix its name with _. This notation appears only on the design document and indicates that the node is linked. Keep these two rules:
Prefix the node name with _. (_Author, _Project)
Only list the primary key (PK) properties. The join requires only the PK, so other fields are omitted for readability.
When to use _ — If this twin is responsible for populating that node’s values (via collection), treat it as a normal node; if another twin already populates it and you just need to link, use _. You do not need to first check whether the node exists in another twin—there is no guarantee that identical names refer to the same node. The decision criterion is whether you are the owner of the data.
The key point: You can create it in the design document, but it does not exist in Neo4j until you merge it. When saving, _ is stripped and a MERGE occurs on the same label (_Project → graph’s Project). This is not a redefinition; it merely references the node with its PK, leaving title, ownership, and display name untouched. Therefore, no new node is inserted when you use an underscore.
You can create it directly with add_node or create in the SDK—no need to edit it later via the web. If you provide a source for the reference node’s PK, collection data will automatically link; otherwise, when calling .save(), only the PK is sent for _Project.
unique — Key that Determines Whether a Node Already Exists
If omitted, the property remains empty. No error occurs; the node is created with an empty field.
Entry
Meaning
@issues.title
The title inside the issues collection of the collected data
@worklog_id
The worklog_id from the collected data
Plain text
The literal string becomes the value (constant)
If the part before @ is an array, a node is created for each element—@issues.title with three items creates three nodes. This is the only way to expand an array into multiple nodes.
We build exactly as drawn in the design document, holding it in our hands. The design document also specifies nodes and edges. Skills only pass values — they do not write any line about which edge goes in which direction.
Zio.node().merge()creates a single node. Edges must be attached directly with merge_relation(). If the number of nodes grows to two or more and even forms a tree, industry‑specific managers will draw the design document and then draw the same diagram again in Python. This bundle takes over that role.
Method
Description
Zio.ontology(twin_id, entry_node=None)
Retrieves one page of the design document. twin_id is the UUID of the design document and is stored as the node’s twin_id attribute unchanged. entry_node is the root node name and is only needed for writing.
.save(data)
Creates nodes and edges exactly as drawn in the design document. data is {node_name: [instances, …]}.
The two arguments are the same as the agent’s “ontology node connection”. The two fields where you pick a design document and an entry node in the agent builder become arguments here.
With this single call, two WbsItem nodes are created, and the edges REPORT_ON, BELONGS_TO, and HAS_SUBTASK are attached together. There is no edge code in the snippet.
Write it exactly as it appears in the design document. Underscore prefixes are kept (_Project). The SDK strips the label — the graph receives Project. Names not present in the design document are quietly ignored.
Instance
If a list, each element is one node. A single dict is also accepted. Attribute names match those in the design document.
Do not include
name, _display, title, twin_id — the SDK attaches these automatically. Including them overrides calculated values.
Edges are attached only between nodes that were passed in this call. Even if the design document shows an edge, if one side is not passed, that edge will not be created.
Therefore only underscore‑prefixed key nodes are passed as keys. The purpose is to find and attach existing nodes; the attributes of those nodes are filled by the design document that created them. Passing only the key means none of the node’s attributes change.
Self‑referencing edges are paired by the design document
Edges that connect the same node, such as in a WBS tree or precedence tasks, are paired by the design document’s “key mapping.” The skill merely records the parent name as an attribute.
Edge
sourceKey
targetKey
HAS_SUBTASK
project_code, item_name
project_code, parent_item_name
PRECEDES
project_code, item_name
project_code, previous_item_name
If the referenced parent does not yet exist, a placeholder node with only a name is created. When the parent’s value arrives later, it will be filled in. This approach was deemed better than breaking the tree.
saved represents the number of items passed, not the number that succeeded. If they differ, see skipped.
written indicates whether something was written rather than whether it succeeded. If the root key is empty and nothing is written, this is a judgment, not a failure — the value simply did not arrive, and at that point a retry is warranted.
Nodes and edges are created in one batch. If something goes wrong midway, nothing is written to the graph. A partially drawn graph does not exist.
Do not create if key is empty
Prevents nodes that cannot be found from being created. The instance is skipped while the rest proceeds.
Idempotent on repeated runs
If a node is missing, it is created; if it exists, it is updated. Re‑passing the same values does not increase node count.
Only update passed fields
For existing nodes, only the fields provided in this call are written. Even if the design document changes, previously written nodes are not rewritten.
The node given as entry_node is the root of this data set. If its key is empty, the entire save operation is aborted — without a root, any subsequent traversal cannot find it. This is why WbsItem was provided as the root in the example above.