Skip to main content

build-gtk

Builds graph tools with Unity Graph Toolkit (GTK) on 6.6+, state machines on 6.7+, and importers for runtime assets. Use this skill for graph, node or state machine editors, or GraphView migrations. Not for Shader Graph, VFX Graph or Animator.

Source facts

Repository
Unity-Technologies/unity-agent-plugin
Last source activity
November 6, 2026 at 16:35
Detected SKILL.md language
English
Stars
622
Forks
68

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
5 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
build-gtk
description
Builds graph tools with Unity Graph Toolkit (GTK) on 6.6+, state machines on 6.7+, and importers for runtime assets. Use this skill for graph, node or state machine editors, or GraphView migrations. Not for Shader Graph, VFX Graph or Animator.
required_editor_version
>=6000.6
# 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 - Use the unity cli (`unity command --format json`) and the `unity-cli` and `unity-pipeline` skills for each step. - 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. - Never leave verification code in the user's script. Never build logging or detection they didn't ask for. See [Final step](#final-step). - Avoid long explanations. - **Graph Toolkit is a built-in module, not a package.** Never add `com.unity.graphtoolkit` to the manifest; it is a deprecated shim. Editor code needs no asmdef reference to use it. - **Use only the public API.** If a draft uses any name from the left column, stop and rewrite it with the right column: | Never write | Write instead | |---|---| | `GraphModel`, `GraphObject`, `GraphTool`, `Stencil`, `BaseGraphTool` | `Graph` and `GraphDatabase` | | `NodeModel`, `PortModel`, `WireModel` | `Node`, `IPort`, `Wire` | | `StateModel`, `TransitionModel`, `ConditionModel` | `State`, `ITransition`, `Condition<T>` | | `GraphViewEditorWindow`, `GraphElementsExtensionMethodsCache`, `ModelView` | the window is provided; `NodeView<T>` on 6000.7+ for custom UI | | `UnityEditor.Experimental.GraphView`, `graphViewChanged`, `Port.Create` | model the tool as `Graph` and `Node` classes; track changes in `OnGraphChanged` | | `com.unity.graphtoolkit` in the manifest | nothing; the module is built in | - **Spell members exactly.** Properties are PascalCase (`FirstConnectedPort`, `IsConnected`), attributes take positional arguments, and IDs are `Hash128`, not strings. Look up any member you have not seen in the docs or references instead of guessing it. - **Every authoring class is `[Serializable]`** (graph, node, state, condition, self transition) and lives in Editor-only code. Otherwise nodes reset or vanish after a domain reload. - **Keep runtime assemblies free of `Unity.GraphToolkit.Editor`.** Guard visualization calls with `#if UNITY_EDITOR`, because the module is Editor-only and any reference to it breaks the player build. - **Use `LoadGraphForImporter` (not `LoadGraph`) inside a `ScriptedImporter`.** The state machine equivalent is `StateMachineDatabase.LoadStateMachineForImporter<T>`. - **Wrap every programmatic edit** in `UndoBeginRecordGraph` / `UndoEndRecordGraph` and call `GraphDatabase.SaveGraph`. Never mutate the graph inside `OnEnable`, `OnDisable` or `OnGraphChanged`; it throws `InvalidOperationException`. ## Step 1 Before you go forward with a workflow or diagnosis: 1. Get the Editor version from the user's message, or else from `m_EditorVersion` in `ProjectSettings/ProjectVersion.txt`, and pick the API from the table below. A version the user names wins over a newer project. Ask only when neither gives it. 2. Open and read the [documentation page(s)](#topic-map) that cover what you intend to do or fix. Where the manual has no page, read the reference file named in [Step 3](#step-3-where-the-docs-stop). 3. Name the file(s) you read in your response. A missing Unity project or unreachable docs do not block the answer: write the code from this skill and its references, say where each file goes, and name what you could not check. This is because your training knowledge about Unity might be out of date, incorrect, or for the wrong Unity version. Graph Toolkit changed significantly between 6000.4, 6000.6 and 6000.7. | Editor version | Available | |---|---| | Older than 6000.4 | Only the retired experimental package (0.x). Its API differs from this skill. Recommend upgrading. | | 6000.4 to 6000.5 | Module present, but without port capacity, type casting, wire and node visualization, USS node styling, or element IDs. | | 6000.6 | The Graph API. | | 6000.7 and newer | Everything above plus the State Machine API, `NodeView<T>` / `StateView<T>` / `ConditionView<T>` custom UI, `[GraphMenu]` / `[BlackboardMenu]` context menus, the `GraphLogger.GraphChanges` change delta, polymorphic and type-following ports, and Blackboard type restriction. | 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. ## Step 2: Start from the graph tool skeleton The `implement-a-graph-tool.md` and `implement-nodes.md` pages explain this in full. When they cannot be fetched, start from: ```csharp [Graph(AssetExtension)] [Serializable] // GraphOptions.SupportsSubgraphs as a second argument class DialogueGraph : Graph { public const string AssetExtension = "dialogue"; [MenuItem("Assets/Create/Dialogue/Dialogue Graph")] static void Create() => GraphDatabase.PromptInProjectBrowserToCreateNewAsset<DialogueGraph>(); } [Serializable] [Node("Dialogue")] class LineNode : Node { protected override void OnDefinePorts(IPortDefinitionContext context) { context.AddInputPort("In").Build(); // untyped: execution flow context.AddInputPort<string>("Text").Build(); context.AddOutputPort("Next").WithCapacity(PortCapacity.Single).Build(); // outputs accept many wires by default } } ``` Different port types do not connect unless `Graph.IsConnectionAllowed(IPort output, IPort input)` allows it; the graph only records the wire, and the importer does the conversion. ### Gotchas | Symptom | Fix | |---|---| | A typed input port refuses a second wire, or an output accepts several | Typed inputs default to `PortCapacity.Single`; untyped ports and outputs to `Multi`. Set `WithCapacity` explicitly | | `GetInputPortByName` or `GetNodeOptionByName` returns the wrong element or null | Port and option names are lookup keys: keep them unique, share a `const` between `OnDefineOptions` and `OnDefinePorts` | | Ports rebuild on every keystroke of a count option | `.Delayed()` on the option | | `AsVertical()` has no effect | Block node ports are always horizontal | | A node lands in an odd Add-menu folder such as `Math/Add/Add` | The first `[Node]` argument is a folder path; the title is appended to it | | `OnEnable` runs several times | Expected on load, reopen and domain reload: keep it idempotent | | Compile error on a class marked `[SerializeReference]` | That attribute is for fields; classes take `[Serializable]` | ## Step 3: Where the docs stop The manual covers the 6.6 Graph API. These parts have no manual page yet, so read the reference file before writing code. Paths are relative to this skill's folder. - **Importer to a runtime asset, and wiring the debug view from runtime code:** [`references/runtime-and-visualization.md`](references/runtime-and-visualization.md). The importer always has this shape: ```csharp var graph = GraphDatabase.LoadGraphForImporter<MyGraph>(ctx.assetPath); // never LoadGraph here if (graph == null) return; // bad path or type: log and stop var start = graph.GetNodes().OfType<StartNode>().FirstOrDefault(); if (start == null) return; // OnGraphChanged already reported it var next = start.GetOutputPortByName("Next").FirstConnectedPort?.GetNode(); // null when unconnected var titlePort = next.GetInputPortByName("Title"); titlePort.TryGetValue<string>(out var title); // the value typed on the node if (titlePort.IsConnected) { /* resolve titlePort.FirstConnectedPort.GetNode() upstream instead */ } ctx.AddObjectToAsset("Runtime", runtime); ctx.SetMainObject(runtime); ``` The runtime asset keeps `Hash128` IDs as `Hash128` and never references `Unity.GraphToolkit.Editor`. - **State machines (6000.7+):** [`references/state-machine-api.md`](references/state-machine-api.md). The core types: ```csharp [StateMachine(AssetExtension)] [Serializable] class EnemyBrain : StateMachine { public const string AssetExtension = "enemybrain"; [MenuItem("Assets/Create/AI/Enemy Brain")] static void Create() => StateMachineDatabase.PromptInProjectBrowserToCreateNewAsset<EnemyBrain>(); } [Serializable] class Patrol : State { } // no ports; the state machine owns transitions [Serializable] [Condition("Distance to player")] class DistanceCondition : Condition<float> // derive from Condition for a valueless trigger { protected override bool DisplayComparisonDropdown => true; } ``` Validation goes in `OnStateMachineChanged(StateMachineLogger)`. An importer walks `GetStates()`, each state's `GetOutgoingTransitions()`, each transition's `GetRules()` and each rule's `RootCondition`. That tree always contains built-in conditions, so handle `IGroupCondition` (recurse, honor `Operation`, a `GroupConditionOperation` of `And` or `Or`) and `IVariableCondition` before matching custom `Condition<T>` types. - **Knowing what changed, and the other 6.7 Graph API additions:** [`references/graph-api-gaps.md`](references/graph-api-gaps.md). On 6000.7+, `logger.GraphChanges.ChangedNodes` reports added and modified nodes. Removed nodes are never reported, so on every version, and for all changes on 6000.6, diff a `[NonSerialized]` `HashSet<Hash128>` of node IDs against `GetNodes()`. ## Topic map The docs are online at `https://docs.unity.com/en-us/engine/<VERSION>/`. Replace `<VERSION>` with the project's Editor version from `ProjectSettings/ProjectVersion.txt`, for example `6000.6` or `6000.7`. Pages are served as markdown when the `.md` suffix is kept. Prefer `WebFetch` over `WebSearch`; it is faster and lands on the exact page. Only fetch what you need. - **GTK index**: `manual/extending-the-editor/gtk-index.md`, the landing page for all GTK manual topics - **Implementing a graph tool**: `manual/extending-the-editor/gtk-index/implementing-a-graph-tool.md`, with these pages under it: - `implement-a-graph-tool.md`: graph class, asset creation, menu item - `implement-nodes.md`: node class, `OnDefinePorts`, discovery rules - `implement-node-options.md`: `IOptionDefinitionContext`, `Delayed`, `ShowInInspectorOnly` - `implement-context-nodes.md`: `ContextNode`, `BlockNode`, `UseWithContext` - `implement-block-nodes.md`: block port rules, horizontal-only ports - `type-cast-ports.md`: `IsConnectionAllowed`, cross-type connections - `add-custom-toolbar-actions.md`: `GraphToolbarElement`, `IGraphWindow` - `add-subgraph-support.md`: `GraphOptions.SupportsSubgraphs`, subgraph ports from Blackboard variables - `graph-processing.md`: `OnGraphChanged`, `GraphLogger`, `GraphLogAction`, fix buttons - **Graph window and panels**: `manual/extending-the-editor/gtk-index/landing-graph-interface.md`, with `graph-window.md`, `blackboard.md`, `graph-inspector.md` and `minimap.md` under it - **Debug graph view** (manual from `6000.7`; the API is the same on 6.6): `manual/extending-the-editor/gtk-index/landing-implementing-debug-graph-view.md`, with `concept-graph-visualization.md`, `task-display-node-progress.md`, `task-display-port-values.md`, `task-display-errors-in-graph.md` and `task-customize-wire-display.md` under it - **Samples**: `https://docs.unity3d.com/Packages/com.unity.graphtoolkit-samples@<PKG_VERSION>/manual/index.html`. Install `com.unity.graphtoolkit-samples` by name in the Package Manager, replace `<PKG_VERSION>` with the version shown there, then import Texture Maker (importer), Visual Novel Director (runtime and live debug view) or Dungeon Graph Generator (building a graph from code). - **Community**: `https://discussions.unity.com/tag/graph-toolkit`, for known issues and workarounds not yet in the docs. ### API reference If the Editor install folder has a `Data/Documentation` folder (for example `.../Unity/Hub/Editor/6000.6.0f1/Editor/Data/Documentation`), read the HTML files in its `en/ScriptReference` folder. Otherwise the Script Reference is online: ``` https://docs.unity.com/en-us/engine/<VERSION>/script-reference/unity/graphtoolkit/editor/<typename>.md ``` Type names are all lowercase with generic arity dropped (`condition.md` for `Condition<T>`). Member pages nest one level deeper: `.../graph/ongraphchanged.md`. The older HTML form also resolves: `https://docs.unity3d.com/<VERSION>/Documentation/ScriptReference/Unity.GraphToolkit.Editor.<Type>.html`. **Graph API (6.6+):** `Graph`, `GraphDatabase`, `GraphOptions`, `GraphLogger`, `GraphLogAction`, `GraphChanges` (6.7), `ChangedNode` (6.7), `ChangeKind` (6.7), `Node`, `NodeAttribute`, `NodeView<T>` (6.7), `IPort`, `IPortDefinitionContext`, `IInputPortBuilder`, `IOutputPortBuilder`, `PortCapacity`, `PortConnectorUI`, `PortDirection`, `INodeOption`, `IOptionDefinitionContext`, `ContextNode`, `BlockNode`, `UseWithContext`, `UseWithGraph`, `ISubgraphNode`, `Subgraph` (attribute), `IVariable`, `IVariableNode`, `VariableKind`, `IConstantNode`, `IGraphWindow`, `GraphToolbarElement`, `GraphMenu` (6.7), `BlackboardMenu` (6.7), `Wire` **State Machine API (6.7+):** `StateMachine`, `StateMachineDatabase`, `StateMachineOptions`, `StateMachineLogger`, `StateMachineLogAction`, `StateMachineChanges`, `State`, `StateAttribute`, `StateView<T>`, `IState`, `ITransition`, `ITransitionRule`, `ICondition`, `IGroupCondition`, `GroupConditionOperation`, `IVariableCondition`, `Condition`, `Condition<T>`, `ConditionAttribute`, `ConditionView<T>`, `ConditionComparison`, `SelfTransition`, `TransitionAttribute`, `ISubgraphState`, `StateMachineMenu`, `ConditionMenu`, `UseWithStateMachine` **GraphVisualization API (6.6+),** namespace `Unity.GraphToolkit.Editor.GraphVisualization`, pages under `.../graphvisualization/<typename>.md`: `Registry`, `Context`, `GraphMotion`, `NodeReference`, `PortReference`, `WireReference`, `StateReference` (6.7), `TransitionReference` (6.7), `ConditionReference` (6.7) ## Final step Do the following checks: 1. Check the project has zero console errors. Use `unity command console status` for counts. Without the Unity CLI, ask the user to select the Editor and report what is displayed in the Console. 2. Create an asset from the new menu item, add every node or state type from the Add menu, connect them, save, close and reopen. The Console must show no errors or warnings. A type missing from the Add menu is abstract, generic, or in another assembly without `[UseWithGraph]` / `[UseWithStateMachine]`. 3. With an importer, confirm the produced runtime object is the main asset. 4. Stop there unless the user asked you to prove it works or you suspect a specific fault. 5. If you do enter Play mode, do it once only to chase a fault you already suspect. Read the world through `unity command script eval --caller plugin --skill build-gtk --code '<snippet>'` rather than adding logging. Take no screenshots as they take too much time. If a check fails, go back and reread the [docs pages](#topic-map) or reference file for that step to find out what you missed. ## Final report Give the user a concise but not dense checklist of what you did and why. If the user needs to follow up
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub