Unity Graph Toolkit (GTK)
Build Editor graph tools and state machine tools on Unity's Graph Toolkit module, using only its
public API in the Unity.GraphToolkit.Editor namespace.
Important
- Create a restore point you can roll back to if your changes fail.
- Do only what's asked. Don't change unrelated assets or files. Avoid long explanations.
- Before you go forward with a workflow or diagnosis, open and read the reference file(s) named in that workflow and the Topic map page(s) that cover the thing you intend to do. Name the file(s) you read in your response. This is because your training knowledge about Unity might be out of date, incorrect, or for the wrong Unity version, and Graph Toolkit changed between 6000.4, 6000.6 and 6000.7.
References
Read these as needed. Paths are relative to this skill's folder.
references/graph-api.md— the Graph API surface: Graph, Node, port and option builders, context and block nodes, subgraphs, variables, validation, toolbar and context menus. Read before writing any graph-tool code.references/state-machine-api.md— the State Machine API (Unity 6.7+): StateMachine, State, Condition, transitions and rules, self transitions, custom views. Read whenever states, transitions or conditions are involved.references/runtime-and-visualization.md— compiling a graph or state machine into a runtime asset with a ScriptedImporter, and showing live execution in the graph editor. Read when the user wants the authored data used in the game or debugged at runtime.references/pitfalls.md— the mistakes that survive compilation. Read before handing off, and whenever the user reports a compile error, an empty Add menu, a missing node, or an exception.
Step 1: Check the Editor version and pick the API
Read m_EditorVersion in ProjectSettings/ProjectVersion.txt before writing code. Graph Toolkit is
an Editor module, so there is no package to install. com.unity.graphtoolkit is a deprecated shim
and must not be added to the manifest.
If the user asks for a state machine tool on an Editor older than 6000.7, say plainly that the State Machine API is not available there. Do not emulate it with the Graph API unless asked.
Mental model
-
Graph Toolkit is an authoring framework only. It draws and persists graphs; it never executes them. The user writes the runtime data model and the code that runs it, usually fed by a ScriptedImporter.
-
One asset type per
GraphorStateMachinesubclass, identified by the file extension passed to[Graph("ext")]or[StateMachine("ext")]. -
Discovery is by reflection. Node, state and condition classes in the same assembly as the graph class are listed automatically. Classes in other assemblies opt in with
[UseWithGraph]or[UseWithStateMachine]. Abstract classes are never listed. -
Every authoring class is
[Serializable]and lives in an Editor-only assembly, either anEditorfolder or an asmdef restricted to the Editor platform. -
Only the public API compiles for users. If a name from the left column appears in a draft, stop and use the right column:
Workflow A: build a graph tool
Read references/graph-api.md now, before writing code; member names and builder chains come from
there, not from memory. Read references/runtime-and-visualization.md as well when step 5 applies.
-
Graph class.
[Graph(AssetExtension)] [Serializable] class MyGraph : Graphwith apublic const string AssetExtension. Add a[MenuItem("Assets/Create/...")]static method that callsGraphDatabase.PromptInProjectBrowserToCreateNewAsset<MyGraph>(). PassGraphOptions.SupportsSubgraphsin the attribute when subgraphs are wanted. -
Node classes.
[Serializable] class MyNode : Node. OverrideOnDefinePortsand end every port builder chain with.Build(). OverrideOnDefineOptionsfor inspector-editable settings, and read them insideOnDefinePortswithGetNodeOptionByName(name).TryGetValue<T>(out var v)when ports depend on them. Call.Delayed()on count-like options so ports are not rebuilt on every keystroke. Use[Node("Category/Path", iconPath, title, stylesheet)]for placement, icon, default title and USS. -
Validation. Override
OnGraphChanged(GraphLogger logger)and report withlogger.LogError,LogWarningorLog, passing the offending node or port as context so the marker appears on it. Never mutate the graph in this callback; put the fix in aGraphLogActionattached to the message, a menu item, or the importer. -
Structure, as requested. Context and block nodes, subgraphs, blackboard variables, type casting through
IsConnectionAllowed, a toolbar element, or a context menu. Details ingraph-api.md. -
Output. A
ScriptedImporterregistered on the same extension compiles the graph into a plain runtime asset. The shape is always the same:The runtime asset and its assembly must not reference
Unity.GraphToolkit.Editor; keepHash128IDs asHash128. Debug views and code-built graphs are inruntime-and-visualization.md. -
Verify as described below.
Workflow B: build a state machine tool (Unity 6.7 and newer)
Read references/state-machine-api.md now; there is no manual walkthrough for this API yet, so that
file and the Script Reference are the only accurate sources for its member names.
- State machine class.
[StateMachine(AssetExtension)] [Serializable] class MySM : StateMachineplus a menu item callingStateMachineDatabase.PromptInProjectBrowserToCreateNewAsset<MySM>(). - States.
[Serializable] class Patrol : State. States have no ports; the state machine owns the transitions. Options declared inOnDefineOptionsappear only in the Graph Inspector. - Conditions.
[Serializable] [Condition("Health")] class HealthCondition : Condition<float>withprotected override bool DisplayComparisonDropdown => truewhen a comparison operator is wanted. Derive fromConditiondirectly for a valueless trigger. Group (And/Or) and variable conditions are built in; do not reimplement them. - Optional. Custom self transitions (
SelfTransition+[Transition(...)]), custom UI throughStateView<T>andConditionView<T>, and[StateMachineMenu]/[ConditionMenu]entries. - Validation. Override
OnStateMachineChanged(StateMachineLogger logger). Same rules asOnGraphChanged. - Output. A
ScriptedImporterloads withStateMachineDatabase.LoadStateMachineForImporter<MySM>, then walksGetStates(), each state'sGetOutgoingTransitions(), each transition'sGetRules(), and each rule'sRootConditiontree. That tree always contains the built-in kinds as well as the user's classes, so the compiler must handleIGroupCondition(recurse, honourOperation) andIVariableCondition(Variable.Name,Comparison,Value) before matching customCondition<T>types.
Editing a graph from code
When a menu item, generator or tool builds or edits an asset, bracket the mutations:
LoadGraph/CreateGraph → UndoBeginRecordGraph("Action") → AddNode, Connect,
port.TrySetValue, CreateVariable → GraphDatabase.SaveGraph(graph) → UndoEndRecordGraph().
The state machine equivalents are UndoBeginRecordStateMachine, Connect(fromState, toState),
SaveStateMachine and UndoEndRecordStateMachine. Mutating inside OnEnable, OnDisable,
OnGraphChanged or OnStateMachineChanged throws InvalidOperationException.
Decisions
Constraints
- Use member names exactly as the references spell them: properties are PascalCase
(
FirstConnectedPort,IsConnected), attributes take positional constructor arguments, and IDs areHash128. When a member is not listed in the references, look it up at the URL pattern below rather than guessing its name or casing, because a guessed member fails to compile and the user cannot tell a typo from a missing feature. - Link to the Script Reference or manual instead of restating them, so the answer stays correct when the docs change.
- Keep runtime assemblies free of
Unity.GraphToolkit.Editor, and put visualization code inside a runtime assembly under#if UNITY_EDITOR, because the module is Editor-only and any reference to it breaks the player build. - Keep the user's existing tool structure and do not restyle or reorganize nodes that were not mentioned, because node and port names are lookup keys that importers and saved assets depend on.
- Do not use Graph Toolkit internals or private types as a workaround, because they are not accessible from user code and change without notice. If the public API cannot do something, say so and point at the community thread list below.
Verify
- Read
references/pitfalls.mdand check the code against it before showing it to the user. - The project compiles with no errors. If the Unity CLI is available, use it to build or run the Editor headless; otherwise ask the user to focus the Editor and report the Console.
- Create an asset from the new menu item, double-click it, add every node or state type from the Add menu, connect them, save, close and reopen. The Console must show no errors or warnings.
- With an importer, select the asset and confirm the produced runtime object is the main asset in
the Inspector.
3b. When you wrote runtime code (an executor, a debug view), add
Debug.Loglines that prove the behaviour, such as the state entered or the node executed, enter Play mode, and read them. Remove or guard them once the behaviour is confirmed. - Re-read
references/pitfalls.mdand fix anything it flags. - If a step fails or the Console reports an error, go back and reread the reference file and the Topic map page for that step before retrying; the fix is usually a member name or a version gate you missed.
Final report
Give the user a short checklist: the files you created or changed and where they go, how to create and open the first asset, what the importer produces, and which Editor version the code targets. List what is left for them to decide or do next, such as more node types, the runtime executor, or the debug view, and any Console error you could not verify because no Editor was available.
Topic map
Prefer WebFetch over WebSearch; it is faster and lands on the exact page. Only fetch what you need.
Replace <VERSION> before fetching:
docs.unity.com/en-us/engine/<VERSION>anddocs.unity3d.com/<VERSION>/Documentation: the project's Editor version fromProjectSettings/ProjectVersion.txt, for example6000.6or6000.7.docs.unity3d.com/Packages/com.unity.graphtoolkit-samples@<VERSION>: the samples package version shown in the Package Manager, for example0.6.
Pages, all under https://docs.unity.com/en-us/engine/<VERSION>/, served as markdown when the .md
suffix is kept:
- Manual index:
manual/extending-the-editor/gtk-index.md - Implementing a graph tool:
manual/extending-the-editor/gtk-index/implementing-a-graph-tool.md, with child pagesimplement-a-graph-tool.md,implement-nodes.md,implement-node-options.md,implement-context-nodes.md,implement-block-nodes.md,type-cast-ports.md,add-custom-toolbar-actions.md,add-subgraph-support.md,graph-processing.mdunder that folder - Graph window and panels:
manual/extending-the-editor/gtk-index/landing-graph-interface.md, withgraph-window.md,blackboard.md,graph-inspector.md,minimap.mdunder it - Script Reference:
script-reference/unity/graphtoolkit/editor/<type>.mdand.../<type>/<member>.md, all lowercase, generic arity dropped (condition.mdforCondition<T>). Example:script-reference/unity/graphtoolkit/editor/graph/ongraphchanged.md. State machine types exist from6000.7. The older formhttps://docs.unity3d.com/<VERSION>/Documentation/ScriptReference/Unity.GraphToolkit.Editor.<Type>.htmlalso resolves, as HTML. - Samples:
https://docs.unity3d.com/Packages/com.unity.graphtoolkit-samples@<VERSION>/manual/index.html. Installcom.unity.graphtoolkit-samplesby name in the Package Manager, then import Texture Maker (importer), Visual Novel Director (custom runtime and debug view) or Dungeon Graph Generator (building a graph from code). - Community: https://discussions.unity.com/tag/graph-toolkit


