Skip to content

feat(vfx): agent control of Unity Visual Effect Graph#227

Open
arghhhhh wants to merge 82 commits into
akiojin:developfrom
arghhhhh:vfx-graph-control-pr
Open

feat(vfx): agent control of Unity Visual Effect Graph#227
arghhhhh wants to merge 82 commits into
akiojin:developfrom
arghhhhh:vfx-graph-control-pr

Conversation

@arghhhhh

Copy link
Copy Markdown
Contributor

Summary

  • Adds complete agent-driven authoring + runtime control of Unity's Visual
    Effect Graph to unity-cli, via reflection over the internal UnityEditor.VFX.*
    API (the entire authoring API is internal) plus the public runtime API.
  • Ships 6 vfx_* tools covering 16 VFX capabilities + an SDF-bake utility, each
    as a full 5-layer vertical (tool catalog -> C# handler -> skill -> tests -> docs).
  • Branch synced onto v0.12.0; baseline is Unity 6000.4.11f1 / VFX Graph 17.4.0.

Changes

  • src/tooling/tool_catalog.rs: registers 6 remote tools (vfx_apply,
    vfx_describe_graph, vfx_list_library, vfx_runtime, vfx_settings,
    vfx_bake_sdf); TOOL_NAMES parity count 136.
  • UnityCliBridge/.../Editor/Handlers/VfxGraphHandler.cs: reflection-based
    authoring + runtime handler (describe oracle, op dispatcher, SDF bake).
  • UnityCliBridge/.../Editor/Core/BridgeCommandRouter.cs: 6 ["vfx_*"] registry
    entries dispatching to VfxGraphHandler.
  • UnityCliBridge/.../Tests/Editor/Handlers/VfxGraphHandlerTests.cs &
    .../Tests/PlayMode/Vfx/VfxRuntimePlayModeTests.cs: EditMode + PlayMode suites.
  • .claude-plugin/plugins/unity-cli/skills/unity-vfx-graph/: skill v0.33.0.
  • docs/tools.md: vfx_* rows + updated tool totals.
  • UnityCliBridge/Assets/VfxFixtures/: committed .vfx/shadergraph/HLSL/mesh
    fixtures; ProjectSettings/VFXManager.asset.

Testing

  • cargo fmt --all -- --check — clean
  • cargo clippy --all-targets -- -D warnings — 0 warnings
  • cargo test --all-targets -- --test-threads=1 — 418 passed, 0 failed
  • cargo run -- skills lint --severity error — 16 skills, 0 violations
  • dotnet test lsp/Server.Tests.csproj — 42 passed, 0 failed
  • cargo llvm-cov --all-targets --fail-under-lines 90 -- --test-threads=1 — 92.13%
  • dotnet test ... /p:Threshold=90 /p:ThresholdType=line — LSP 99.52%
  • Unity 6000.4.11f1: EditMode VfxGraphHandlerTests 150/0, PlayMode
    VfxRuntimePlayModeTests 8/0, clean recompile (errorCount: 0)

Closing Issues

None

Related Issues / Links

Checklist

  • Tests added/updated
  • Lint/format passed (cargo clippy, cargo fmt; svelte-check N/A)
  • Documentation updated (docs/tools.md, unity-vfx-graph skill)
  • Migration/backfill plan included (n/a — no schema/data change)
  • CHANGELOG impact considered (additive feature; no breaking change)

Context

This lands 78 VFX commits as a first-class contribution. The branch was synced
onto upstream v0.12.0: 3 conflicts resolved (tool_catalog.rs count, the new
BridgeCommandRouter dispatch, manifests), the VFX handlers migrated into the
new router registry, and the project baseline moved to Unity 6000.4.11f1 / VFX
Graph 17.4.0 (SRP packages are editor-pinned builtins). The full EditMode +
PlayMode suites pass against 17.4 — no internal-API reflection drift.

Risk / Impact

  • Affected areas: additive — 6 new vfx_* tools, the bridge router gains 6
    entries, the embedded Unity package gains a handler + tests, project baseline
    Unity/VFX Graph bumped to 6000.4.11f1 / 17.4.0. No existing tool behavior
    changes.
  • Rollback plan: revert the PR; no data/schema migration involved.

Notes

  • The handler is reflection-only (no compile-time VFX assembly reference), so
    the bridge still compiles where VFX Graph is absent (e.g. the Unity 2022
    manifest variant).
  • The outcome-layer agent eval (scripts/vfx-agent-eval/,
    tests/fixtures/vfx-agent-eval/) is kept fork-only and is not in this branch;
    the VFX skill-routing rows are included.
  • Please add the gwt-spec label to gwt-spec: vfx-graph-control (Unity Visual Effect Graph authoring + runtime control) #226 — it was opened from a fork account
    without label permissions, but its title + body markers identify it as a
    gwt-spec domain SPEC.

akiojin and others added 30 commits June 2, 2026 20:36
The skills linter test imported std::os::unix::fs::symlink unconditionally,
which broke `cargo test` on Windows. Gate the import and the symlink-creating
test with #[cfg(unix)] so the test suite builds on all platforms.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduce vfx_describe_graph, vfx_list_library, and vfx_apply across every
layer so they are native unity-cli tools rather than raw-only additions:

- Unity bridge handler (VfxGraphHandler) driving the internal UnityEditor.VFX
  authoring API via reflection, with read-back, library discovery, and an
  add_block mutation; wired into the host dispatch switch.
- Rust tool catalog: names, explicit param schemas, read-only flags for the
  two query tools, parity-count bump, and per-tool schema unit tests.
- unity-vfx-graph skill (Skill Contract v1) with runtime checklist and the
  .claude/.agents symlinks; unity-asset-management cross-listed as a sibling.
- EditMode contract tests (argument validation / op routing) and a
  docs/tools.md Visual Effect Graph section.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Consolidate VFX development into the UnityCliBridge test project so the
authoring commands have real, CI-runnable coverage:

- Add com.unity.visualeffectgraph 17.3.0 to the test project (URP already
  present); VFXManager + lockfile updated by the import.
- Commit a Minimal.vfx fixture under Assets/VfxFixtures.
- Gate behavioral tests behind a UNITY_VFX_GRAPH versionDefine so the test
  assembly still builds without the package; add tests that describe the
  fixture and add a Turbulence block via VfxGraphHandler against a copy.

Verified: all VfxGraphHandlerTests pass in EditMode (6 methods, incl. the
two behavioral ones) in the consolidated project.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- vfx_describe_graph now reports each block's index + [VFXSetting] values,
  making setting changes verifiable (the Tier-1 oracle this op depends on).
- vfx_apply gains op "set_block_setting": target a block by (contextType,
  blockIndex), convert the value to the field type (e.g. string -> enum),
  SetSettingValue, persist. Adds shared FindContext/FindField/Persist helpers
  (AddBlock refactored onto them).
- tool_catalog: widen vfx_apply schema (blockIndex, setting, value).
- Tests: 2 contract + 1 behavioral (set Turbulence NoiseType -> Perlin,
  verified via describe); all VfxGraphHandlerTests pass in EditMode.
- Skill: document the op, bump to 0.2.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- vfx_describe_graph now reports per-context index and inputs/outputs flow
  links (via VFXContext.inputContexts/outputContexts), making context
  linking verifiable.
- vfx_apply gains op "add_context": create a context from a VFXLibrary
  descriptor (graph.AddChild), with optional linkFrom to flow an existing
  context into the new one via VFXContext.LinkTo (data auto-wires). No-match
  errors list available context names for discovery.
- tool_catalog: widen vfx_apply schema (contextName, linkFrom, fromIndex,
  toIndex).
- Tests: 1 contract + 1 behavioral (add a Point output linked from Update,
  assert 5 contexts and Update has 2 outputs); all VfxGraphHandlerTests pass
  in EditMode. Verified live with zero console errors.
- Skill: document the op, bump to 0.3.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- vfx_describe_graph now reports an operators array and, for every block and
  operator, input/output slots with their resolved links (node address +
  slot index) — the oracle for slot wiring.
- vfx_apply gains add_operator (VFXLibrary.GetOperators descriptor ->
  graph.AddChild) and link_slots (connect a from-output slot to a to-input
  slot via VFXSlot.Link, with from/to addressed as {node,...,slot}).
- vfx_list_library gains kind (block|operator|context) for discovery.
- tool_catalog: widen vfx_apply (operatorName, from, to) and vfx_list_library
  (kind) schemas; refresh descriptions.
- Tests: 3 contract + 2 behavioral (add operators, wire output->input, assert
  links via describe); all 16 VfxGraphHandlerTests methods pass in EditMode.
- Skill bumped to 0.4.0; docs/tools.md updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add exposed blackboard parameters (VFXParameter) via vfx_apply add_parameter
(name/type/default value/tooltip/category/exposed), extend vfx_describe_graph
with a parameters array, support linking a parameter's output slot into a
block/operator input via link_slots (node kind "parameter"), and add
kind=parameter to vfx_list_library. Covers authoring half of Blackboard (akiojin#9).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New first-class vfx_runtime tool drives a scene VisualEffect via its public
UnityEngine.VFX API (reflection): set_asset, set_float/int/bool/vector2-4,
send_event, reinit, get_state. Completes the runtime-verification machinery for
Blackboard (akiojin#9) — an exposed float can be created, linked into a slot, and
changed at runtime with the value round-tripping through HasFloat/GetFloat.
Reused later by Events/Instancing. Includes EditMode round-trip test, contract
test, Rust catalog entry + schema, skill + docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…kiojin#6)

Add the link_flow op (context->context flow edge via VFXContext.LinkTo, endpoints
by contextType or index), optional settings on add_context (e.g. an Event
context's eventName), and per-context settings in vfx_describe_graph. Together
with the existing vfx_runtime send_event this proves Events breadth: a custom
named Event context can be authored, flow-linked into Spawn, and triggered at
runtime. Includes EditMode authoring test + contract test, catalog descriptions,
skill + docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Align VfxGraphHandler with the package's handler style (ComponentHandler et al.):
validation failures now return `new { error = ... }` and each public entry point
(DescribeGraph, ListLibrary, Apply, Runtime) wraps its body in try/catch that
logs via BridgeLogger and returns `{ error = ex.Message }`, instead of throwing
into the host's INTERNAL_ERROR envelope. Required-arg checks are quiet early
returns; only unexpected errors are logged. Contract tests updated to assert the
returned error field. Success results stay JObject (also a package idiom).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
set_bounds switches the Init context's VFXDataParticle boundsMode
(Manual/Recorded/Automatic) and writes the bounds AABox center/size and
boundsPadding when supplied. boundsMode lives on the data, not the
context, but VFXBasicInitialize bridges GetSettings to the data so it
already surfaces on the Init context's settings map in describe.

Extends the describe oracle so the manual extents are verifiable:
contexts now emit inputSlots/outputSlots (previously only blocks and
operators did), and every slot carries its resolved value. ToJToken
hand-serializes Vector2/3/4, Color, and any UnityEditor.VFX /
UnityEngine.VFX struct (e.g. AABox) by public fields — Newtonsoft
recurses through Vector3.normalized otherwise.

Closes the bounds pass-1 breadth proof. Recording-mode capture stays
Pass-2/manual (interactive editor-only).
add_sticky_note appends a StickyNoteInfo to VFXGraph.UIInfos.stickyNoteInfos
with title/contents/position(Rect)/colorTheme/textSize. The notes sit on
the VFXUI ScriptableObject sidecar, not the model graph; reach it via
graph.UIInfos (auto-creates) and the nested type UnityEditor.VFX.VFXUI+
StickyNoteInfo. StickyNoteInfo is a plain [Serializable] class with public
fields (not VFXModel), so go through FindField + Activator.CreateInstance
rather than Prop/SetSettingValue.

Describe gets a top-level stickyNotes array (index/title/contents/position/
colorTheme/textSize/theme). ToJToken now hand-serializes UnityEngine.Rect
alongside the Vector and Color structs.

Closes the sticky-notes pass-1 breadth proof. Update/delete/reorder stay
Pass-2.
set_instancing writes VisualEffectResource.instancingMode (enum, live
values include Auto/Disabled/ForceOn) and instancingCapacity (uint) on
the asset behind a .vfx graph. Reaches the resource via the same
graph.visualEffectResource accessor Persist uses; coerces JSON ints
through Convert.ChangeType so the uint capacity property accepts them.
A SerializedObject fallback on m_Infos.m_InstancingCapacity covers
future package versions that drop the public setter.

Describe now reports a top-level instancing: {mode, capacity} block.

Closes the instancing pass-1 breadth proof (authoring side). The
3-gate reconciliation (Preference master + Asset Mode + component flag)
and multi-instance runtime rendering stay Pass-2.
Custom HLSL needs no dedicated op. The block descriptor "Custom HLSL"
(category HLSL) and operator (Operator/HLSL) compose through the
existing add_block/add_operator paths; the inline source field
m_HLSLCode is a [VFXSetting] writable via set_block_setting.

The describe oracle hid m_HLSLCode because GetSettings(false, Default)
uses HasFlag(filter), and m_HLSLCode lacks the InGeneratedCodeComments
bit that Default requires. Flipping to listHidden=true surfaces every
[VFXSetting] regardless of visibility — backward-compatible: existing
settings still appear, previously-hidden ones additionally do.

EditMode test authors a Custom HLSL block on Update, writes an inline
function via set_block_setting, and asserts describe reports the
stored m_HLSLCode.

Closes the Custom HLSL pass-1 breadth proof. ShaderInclude external
file mode, function selector, and operator-side source-setting (needs
a new set_operator_setting op) stay Pass-2.
Two rigour gaps were identified after the initial Custom HLSL proof:
slot resync from the custom signature was unverified, and a Tier-2
compile-clean assertion was missing (bad HLSL silently leaves the
asset present in describe).

vfx_describe_graph now accepts an opt-in includeErrors flag. When set,
it constructs a fresh VFXErrorReporter, walks the graph (+ contexts +
blocks + operators + parameters) calling each model's GenerateErrors
into it, then reads m_Errors by reflection and emits one JObject per
entry. Off by default — describe stays cheap unless callers ask.

The Custom HLSL EditMode test now asserts both gaps:
- writing m_HLSLCode with a single-`scale`-input function collapses
  the block's inputSlots from _offset+_speedFactor to a single _scale
- no Error-tier validation entries exist after the edit (filtering the
  Minimal fixture's pre-existing NeedsRecording Warning)
create_subgraph_asset copies the VFX package's default subgraph
templates (DefaultSubgraphBlock.vfxblock / DefaultSubgraphOperator.
vfxoperator) into a target path. It's the only vfx_apply op whose
target is its own new path rather than an existing parent graph, so
ApplyCore's assetPath guard now exempts it (catalog required dropped
to ["op"]; handler enforces per-op).

set_block_setting now detects UnityEngine.Object-derived fields and
loads asset-path strings via AssetDatabase rather than asking
Newtonsoft to deserialize a ScriptableObject. This is the lever that
makes m_Subgraph writable from a JSON value.

ToJToken handles UnityEngine.Object early — emits {type, name,
assetPath} instead of recursing through GameObject/Transform. Applies
to every Object-typed setting the oracle reports, not just subgraph
references.

The EditMode test creates a Block subgraph asset, references it from
an Empty Subgraph Block in Update, and asserts describe resolves
m_Subgraph back to the created asset path — full round-trip across a
two-asset boundary.

Closes the Subgraph (Block) pass-1 breadth proof. Operator subgraph
needs a Pass-2 set_operator_setting op; System (.vfx) subgraph and
convert-selection stay Pass-2 too.
…Id oracle

A particle system is just Init→Update→Output sharing one VFXDataParticle,
auto-merged by VFXContext.LinkTo. No new authoring op required — chains
build from existing add_context + link_flow primitives.

Describe now emits dataInstanceId per context (instance id of GetData()
cast to UnityEngine.Object). Equal ids prove system membership; different
ids prove disjoint systems. This is the oracle that turns "I added some
contexts" into a verifiable "I built a system."

EditMode test takes the Minimal fixture (one existing system) and builds
a SECOND system from scratch: adds Init+Update+Output, link_flow's them
by index, then asserts the new chain's contexts share one dataInstanceId
distinct from the original system's. Tier-2 includeErrors=true gate
confirms zero Error-tier validation entries.

Descriptor gotcha: the Output context's full library name is
"Output Particle|Unlit|Quad", not "Output Particle|Quad" — captured in
HANDOFF.
vfx_list_library kind:"template" scans the VFX package's template
directory (VisualEffectAssetEditorUtility.templatePath) and returns the
6 built-in starter templates with on-disk paths.

create_from_template instantiates a fresh .vfx by calling the package's
static UnityEditor.VisualEffectAssetEditorUtility.CreateTemplateAsset
(copies the template's serialized graph + imports). targetPath = new
.vfx; template = a name (stem, resolved against the template dir) or an
explicit .vfx path. Asset-creation op, so exempt from ApplyCore's
assetPath guard (alongside create_subgraph_asset).

EditMode tests: list reports >0 templates incl. a Minimal one; create
instantiates 03_Simple_Burst and asserts the result describes as a real
multi-context graph with zero Error-tier validation entries.

Closes the Templates pass-1 breadth proof. Insert-into-open-graph and
designate-custom-template stay Pass-2.
New first-class tool (akiojin#12 Project Settings, Pass-1 breadth proof) reading
and writing UnityEngine.VFX project settings in ProjectSettings/VFXManager.asset.

- VfxGraphHandler.Settings: op `get` reports a `properties` block (public
  static VFXManager props — fixedTimeStep/maxDeltaTime, round-trip on re-read)
  plus a `serialized` block (asset fields m_MaxCapacity/m_MaxScrubTime/
  m_BatchEmptyLifetime). op `set` writes through the static property setter
  when one exists (via:"property"), else the matching serialized field
  m_PascalCase (via:"serialized").
- 5-layer vertical: catalog name+schema+description (parity count 133→134,
  +unit test), host case, skill section + example, docs/tools.md row.
- Tests: 3 contract (unsupported op, set without setting/value) + 2 behavioral
  (get reports fixedTimeStep/maxDeltaTime; set fixedTimeStep round-trips via
  re-read, restored in finally). All 45 EditMode tests green, 0 skipped.

Verified live via raw: get returns current values; set fixedTimeStep=0.02
re-reads as 0.02; maxCapacity exercises the serialized fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…refs

Pass-1 breadth proof for Preferences (akiojin#13). Reuses the existing vfx_settings
tool with a new `scope` param (default "project"; "preferences" routes to
EditorPrefs via UnityEditor.VFX.VFXViewPreference).

- VfxGraphHandler: VFXViewPreferenceType + a canonical 11-entry preference
  table (propName, keyConstName, type). GetVfxPreferences reflects each
  public static property — instancingEnabled, displayExperimentalOperator,
  multithreadUpdateEnabled, forceEditionCompilation, advancedLogs,
  cameraBuffersFallback (enum→name), authoringPrewarm{Step,Max}, ...
- SetVfxPreference resolves the key constant by reflection, calls the
  matching EditorPrefs.SetBool/SetInt/SetFloat, invalidates the cache via
  VFXViewPreference.SetDirty(), then re-reads through the canonical property
  to confirm the round-trip. Result echoes the resolved editorPrefsKey
  (e.g. "VFX.InstancingEnabled").
- Catalog: schema widened with `scope` string; description updated to cover
  both scopes. Tool-level mutating unchanged (parity count stays 134).
- Tests (3 new, total 48 EditMode, 0 skipped):
  * contract: unknown pref name returns a descriptive error listing the
    11 known names;
  * behavioral get: properties block surfaces instancingEnabled,
    displayExperimentalOperator, multithreadUpdateEnabled;
  * behavioral set: instancingEnabled flips and round-trips via re-read,
    editorPrefsKey resolves to the package's "VFX.InstancingEnabled"
    constant, restored in finally.
- Skill + docs: split scope:project / scope:preferences examples and call
  out the Instancing master gate (gate akiojin#1 of akiojin#16's 3-gate reconciliation).

Verified live via raw: get scope:preferences surfaces all 11 prefs;
set instancingEnabled=false re-reads as false; set
authoringPrewarmStepCountPerSeconds=40 (int) round-trips; restored.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s-1 complete

The last Pass-1 breadth checkbox. No new op, no oracle extension — Attributes
compose entirely from add_block + set_block_setting + add_operator:

- All `Set <Attribute>` blocks ship as descriptor `|Set|_<Name>` (Color,
  Position, Lifetime, ...) and instantiate the single SetAttribute block
  class with the `attribute` [VFXSetting] pre-wired to the descriptor's
  attribute name.
- All `Get <Attribute>` operators ship as descriptor `Get|_<Name>`
  (Position, Direction, ...) and instantiate VFXAttributeParameter.
- Composition mode (Overwrite/Add/Multiply/Blend), Random, Source, and
  per-component channels are ordinary [VFXSetting] fields — set_block_setting
  already writes them; describe already surfaces them.

Behavioral test (49 EditMode tests now, 0 skipped):
- add_block `|Set|_Color` → SetAttribute on Init,
  set_block_setting Composition=Add (round-trips via describe),
- add_operator `Get|_Position` → VFXAttributeParameter,
- includeErrors:true reports zero Error-tier validator issues.

Skill: adds an Attributes paragraph calling out the load-bearing `|`/`|_`
separators in descriptor names (agents will trip on them otherwise) +
discovery via vfx_list_library, plus a corresponding example.

Pass-1 breadth is now 16/16 — the project enters the Pass-2 depth sweep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…kiojin#5)

Pass-2 sweep begins. New `vfx_apply` op `set_slot_value` writes a constant
into an unlinked input slot, addressed by the same `{node, …address, slot}`
shape as a `link_slots` endpoint. The bare op coerces the JSON `value` to the
slot's value type (number/bool/[x,y,z] vector/[r,g,b,a] color, enums); an
optional `subPath` walks into compound value structs via the box-and-write
trick generalized to arbitrary depth (`["center"]`, `["size","x"]`), leaving
sibling components untouched.

Verifiable through the existing oracle: every slot already carries its resolved
`inputSlots[].value` in vfx_describe_graph. Verified live (scalar Rate=42.5,
bounds.center/size.x nested writes, whole-vector padding) and recompiles clean
(Tier-2 includeErrors → 0 Error-tier entries).

5-layer vertical: handler op + reused ResolveNode/GetSlot/Persist helpers;
catalog schema gains `target`/`subPath` params + description; skill examples +
prose; docs/tools.md row; 3 behavioral + 2 contract EditMode tests (all green,
59 passed / 0 failed / 0 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pass-2 companion to link_slots. New `vfx_apply` op `unlink_slots` removes a
slot connection: `target` is the input-slot endpoint `{node, …address, slot}`
(same shape as a link_slots endpoint), resolved via the shared
ResolveNode/GetSlot helpers. By default UnlinkAll(recursive, notify) clears
every link on the slot (input slots hold one link in VFX, so this is
unambiguous); an optional `from` output-slot endpoint unlinks only that edge
via VFXSlot.Unlink(other). Returns linksRemoved/remainingLinks.

Verifiable through the existing oracle: describe emits inputSlots[].hasLink /
links, so an unlink flips hasLink false / empties links. Verified live (link
two operators → unlink → hasLink True→False, linksRemoved 1; from-specific
edge path; missing-target error) and recompiles clean (0 Error-tier).

5-layer vertical: handler op + LinkCount helper; catalog description (target/
from/to params already present); skill example + prose; docs/tools.md row;
1 behavioral + 1 contract EditMode test (all green, 61 passed / 0 failed /
0 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…iojin#4)

Symmetrical to set_block_setting, for operators. New `vfx_apply` op
`set_operator_setting` writes a [VFXSetting] field on a graph operator addressed
by `operatorIndex`. Reuses the setting-coercion path (extracted into a shared
`CoerceSettingValue` helper, which also handles UnityEngine.Object fields by
asset path — so an Operator subgraph's `m_Subgraph` works the same way the block
side does).

Oracle extension (prerequisite): `vfx_describe_graph` now emits `settings` per
entry in the `operators` array via the existing ModelSettings helper — without
it the write would be unverifiable.

Unblocks the Operator subgraph reference path and Custom HLSL operator source.
Verified live: set `m_OperatorName`/`m_HLSLCode` on a Custom HLSL operator, the
single-arg HLSL signature reshaped the operator's input slots to one `k` port
(real model resync), round-tripped through `operators[].settings`, recompiled
clean (0 Error-tier).

5-layer vertical: handler op + shared helper + oracle; catalog description
(operatorIndex/setting/value params already present); skill example + prose;
docs/tools.md row; 1 behavioral + 2 contract EditMode tests (all green,
64 passed / 0 failed / 0 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ontexts (akiojin#1/akiojin#2/akiojin#4/akiojin#9)

Four new `vfx_apply` ops sharing the "locate by address → unlink → RemoveChild
→ persist" shape:
- remove_block      — {contextType, blockIndex} → context.RemoveChild
- remove_operator   — {operatorIndex}           → graph.RemoveChild
- remove_parameter  — {parameterIndex}           → graph.RemoveChild
- remove_context    — {contextType} or {index}   → graph.RemoveChild

Cascade contract (investigated against the 17.3 package source): VFXModel.
RemoveChild does NOT unlink a removed node's data slots, and VFXContext.
OnRemoved does NOT drop flow edges — both would leave dangling links in the
nodes on the other end. So every op explicitly unlinks first via a shared
UnlinkContainerSlots helper (UnlinkAll on each top-level slot), and remove_context
additionally calls VFXContext.UnlinkAll() for flow edges. Each response reports
remaining* counts.

Verified live + EditMode: add-then-remove each kind; removing a linked operator
leaves the survivor's output link-free; removing the Output context clears
Update's downstream flow edge; all recompile with zero Error-tier (no dangling
refs). Required-arg checks precede LoadGraph (contract tests use a fake path).

Catalog: added operatorIndex/parameterIndex/index top-level params (also
retroactively completes set_operator_setting's first-class schema) + description.
5-layer vertical: 4 behavioral + 2 contract EditMode tests (70 passed / 0 failed
/ 0 skipped); skill examples + prose; docs/tools.md row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ta settings (akiojin#2)

New `vfx_apply` op `set_context_setting` writes a [VFXSetting] field on a
context addressed by `contextType` or `index`. One op covers two addressing
styles: it tries the context's own field first (Spawn loopDuration/loopCount/
delay, Update ageParticles/reapParticles/integration, Output blendMode/uvMode/
shader), then falls back to the context's particle data via GetData() — the same
bridge set_bounds uses — so Init `capacity`/`stripCapacity`/`boundsMode` resolve
too. The response's `via` field reports `context` vs `data`.

Reuses the shared CoerceSettingValue helper and ResolveContextRef. Verifiable
through the existing oracle: describe already surfaces both context- and
data-level settings on `contexts[].settings`.

Verified live + EditMode: Spawn loopDuration=Constant (via context), Update
ageParticles=false (via context), Init capacity=256 (via data), Output
blendMode=Additive (via context) — all round-trip through describe and recompile
clean (0 Error-tier). Required-arg checks precede LoadGraph.

5-layer vertical: handler op; catalog description (contextType/index/setting/
value params already present); skill examples + prose; docs/tools.md row;
1 behavioral + 2 contract EditMode tests (73 passed / 0 failed / 0 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…/max (akiojin#9)

Round out add_parameter so an agent can declare the full exposed-parameter
palette, not just Float:
- Full type matrix verified end-to-end: Bool/Int/Uint/Float/Vector2/3/4/Color/
  Texture2D/Texture3D/Cubemap/Gradient/Animation Curve/Mesh.
- Value coercion fixed per type: routed through a new ParamCoerce helper that
  uses CoerceToType for the math structs Newtonsoft can't build ([x,y,z] vectors,
  [r,g,b,a] color) and loads UnityEngine.Object types (Texture/Mesh) from an
  asset-path string. Previously only Newtonsoft-buildable primitives worked.
- Descriptor names carry spaces ("Vector 3", "Texture 2D"); added a
  space-insensitive match so "Vector3"/"Texture2D" resolve too.
- Constant (non-exposed) params via exposed:false.
- min/max numeric Range: sets VFXParameter.valueFilter=Range (enum parsed off the
  property's own type) then min/max via the public properties.

Oracle: describe's parameters[] now emits valueFilter/min/max alongside the
existing fields, so ranges round-trip.

Verified live (all 13 types + Int/Float ranges + non-exposed constant +
"Texture 2D" spaced form) and recompiles clean (0 Error-tier). 5-layer vertical:
handler + ParamCoerce helper + oracle; catalog min/max params; skill examples +
prose; 1 behavioral EditMode test (74 passed / 0 failed / 0 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the operator-subgraph half of akiojin#8. The pieces already existed
(create_subgraph_asset kind:"operator" copies DefaultSubgraphOperator.vfxoperator;
set_operator_setting m_Subgraph lands the Object-by-path ref via CoerceSettingValue)
but nothing proved them composing — this also retroactively validates that
set_operator_setting's Object-field branch works for operator subgraphs (only the
block side was asserted before).

New EditMode behavioral test: create an operator subgraph asset, add an
"Empty Subgraph Operator" (VFXSubgraphOperator), set m_Subgraph to the asset
path, and assert describe surfaces operators[].settings.m_Subgraph as
{type:VisualEffectSubgraphOperator, name, assetPath} with zero Error-tier.
Verified live first (ref resolves, recompiles clean), no handler change needed.

Skill updated with the operator-subgraph example + prose (both kinds now
documented as verified end-to-end).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
arghhhhh and others added 28 commits June 23, 2026 19:49
…ators (akiojin#1/akiojin#4)

Add two vfx_apply ops that clone a block or graph operator via the editor's
VFXMemorySerializer.DuplicateObjects (mirrors VFXContextController.DuplicateBlock):
the clone carries the same [VFXSetting]s + slot values with fresh GUIDs, slots
unlinked. duplicate_block takes contextType+blockIndex, with optional `index`
insert position and `toContextType` to copy into another compatible context
(VFXContext.Accept-validated, like move_block). duplicate_operator mirrors it by
operatorIndex. Shared DuplicateModelViaSerializer helper. Closes akiojin#1's and akiojin#4's
copy/paste/duplicate boxes.

5-layer vertical: tool_catalog op-list + docs/tools.md + unity-vfx-graph SKILL.md
updated (no new params — reuses existing vfx_apply schema); 4 EditMode tests
(1 contract + 3 behavioral: within-context clone fidelity, cross-context copy,
operator clone). All 123 VfxGraphHandlerTests green; describe-verified + clean
recompile via the probe loop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build Initialize Particle Strip -> shared Update Particle -> Output
ParticleStrip|Shader Graph|Quad via add_context + link_flow and assert
the three contexts share one ParticleStrip VFXData (distinct from the
original particle system) with no Error-tier validation. Compose-only,
no new op.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Output Particle|Unlit|Mesh particle chain shares one VFXData; a
standalone Output Single Mesh (VFXStaticMeshOutput) is its own disjoint
single-context system and force-disables instancing
(disabledReason=MeshOutput). Compose-only, no new op.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Set a particle/spawner system's display label, addressing the system by
any one member context (contextType/index) + name. Routes through the
static VFXSystemNames.SetSystemName: particle systems write the shared
VFXData.title (every Init/Update/Output member reports it), Spawners
write the context label. Describe gains a per-context systemName field
(VFXSystemNames.GetSystemName). 5-layer vertical: catalog op-list, handler
op + oracle, skill, EditMode contract + behavioral tests, docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
One Spawner fans out to two disjoint particle systems (each keeps its own
VFXData despite the shared spawner) and also controls a second Spawner via
its Start flow input (spawner->spawner chaining). Compose-only, no new op.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
create_subgraph_asset gains kind:"system" — creates a plain .vfx via
VisualEffectAssetEditorUtility.CreateNewAsset (no .vfxblock/.vfxoperator
template). The parent references it via add_context "Subgraph" +
subgraphPath: VFXSubgraphContext isn't in the node library, so AddContext
special-cases it (CreateInstance + AddChild + SetSettingValue m_Subgraph),
mirroring VFXConvertSubgraph. Describe surfaces the reference as
contexts[].settings.m_Subgraph {type,name,assetPath} (existing Object
oracle). EditMode test builds a populated system subgraph, references it,
asserts the reference + clean recompile. Skill v0.15.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…jin#8)

An exposed parameter added inside an operator subgraph asset
(add_parameter exposed:true) automatically surfaces as an input slot on
the parent's subgraph operator node. Compose-only proof + EditMode test;
skill v0.16.0 documents the expose-input flow.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
akiojin#8)

add_parameter gains an isOutput flag: a parameter with isOutput=true
becomes a subgraph OUTPUT (VFXSubgraphOperator.OutputPredicate), surfacing
as an output slot on the parent's subgraph operator node. The model
property setter swaps the param's slot output->input and forces non-exposed,
so it is set last (the swap preserves the value). Describe gains
parameters[].isOutput. Catalog schema + skill v0.17.0 + EditMode test.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…kiojin#8)

A block subgraph asset holds a single BlockSubgraph context whose
m_SuitableContexts [VFXSetting] (flags enum Spawner/Init/Update/Output +
combos, default InitAndUpdateAndOutput) controls which contexts accept the
subgraph block. Set it with the existing set_context_setting; describe
already surfaces it in contexts[].settings. Compose-only proof + EditMode
test; skill v0.18.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Setting uvMode:"Flipbook" surfaces a flipBookSize input slot on the Output
(a FlipBook x/y grid, set via set_slot_value subPath); flipbookBlendFrames
and flipbookMotionVectors are plain [VFXSetting] bools. Compose-only proof
over existing set_context_setting + set_slot_value + EditMode test. Also
documents shaderGraph-asset assignment (already wired via the Object-by-path
set_context_setting branch; positive test fixture-blocked on a VFX-target
.shadergraph). Skill v0.19.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…kiojin#2)

set_context_setting gains a composed-settings fallback: when a setting
isn't a direct [VFXSetting] field on the context/data, resolve it through
the model's virtual GetSetting (which surfaces composed-output nested
settings + their owning instance) and write via SetSettingValue
(response via:"context-composed"). This unblocks assigning a
ShaderGraphVfxAsset to the dedicated Shader Graph output
(VFXComposedParticleOutput) whose shaderGraph field lives on a nested
shading sub-object — assigning to a plain Unlit output instead raises
WrongOutputShaderGraph. Adds a committed VFX-target shader graph fixture
(VfxUnlit.shadergraph, Support VFX Graph enabled) + EditMode test.
Skill v0.20.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move a sticky note from index to toIndex within VFXUI.stickyNoteInfos
(the array position is the note's order; StickyNoteInfo has no order
field). Mirrors the reorder_block/reorder_parameter shape. Describe's
stickyNotes[] reflects the new order. 5-layer: catalog op-list + handler
op + skill v0.21.0 + behavioral & contract tests + docs. Fit-to-text is a
UI text-measurement with no model-level size -> out of scope headless.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…kiojin#11)

insert_template clones every top-level node (context/operator/parameter)
of a built-in template into an EXISTING graph (vs create_from_template,
which makes a new asset), preserving the template's internal flow + slot
links and nested blocks via VFXMemorySerializer.DuplicateObjects, then
AddChilds the clones as a new disjoint system. The GraphView's merge path
(VFXCopy/VFXPaste) is Controller/View-coupled; this is the model-level
equivalent (a template is self-contained, so no boundary inference).
Factored a shared ResolveTemplateFile helper (also used by
create_from_template). 5-layer: catalog op-list + handler op + skill
v0.22.0 + behavioral & contract tests + docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…kiojin#12)

GetVfxSettings now surfaces the VFXManager compute/empty shader refs +
runtime-resources ScriptableObject (m_IndirectShader/m_CopyBufferShader/
m_PrefixSumShader/m_SortShader/m_StripUpdateShader/m_EmptyShader/
m_RuntimeResources/m_RenderPipeSettingsPath) as {type,name,assetPath}, and
AssignSerialized gained an ObjectReference branch so set writes them by
asset path (empty clears). These are usually Unity-managed defaults —
surfaced for inspection, overridable when needed. EditMode test does a
safe cross-assign round-trip with restore (VFXManager.asset stays clean).
Skill v0.23.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…kiojin#1)

link_slots/unlink_slots gain an `activation:true` flag on the to/target
block endpoint that targets the block's special activationSlot
(`_vfx_enabled`) instead of an indexed input slot, via a new shared
ResolveInputSlot helper. Describe surfaces blocks[].activationSlot
(name/valueType/value/links) so link-driven activation is verifiable.
Drives a block on/off per particle/frame from any bool graph output,
vs set_block_enabled's static toggle. akiojin#1 Blocks now fully complete.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
rename_operator_input (SetOperandName) + reorder_operator_input
(OperandMoved, moves the matching input slot so links survive) for
cascaded numeric operators (Add/Multiply/Append-style). The operand
name drives the input slot name, so describe's existing
operators[].inputSlots[].name oracle verifies both. Non-cascaded
operators return a clear error. akiojin#4 Operators now fully complete.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
reorder_category moves a whole blackboard category within VFXUI.categories
(list position = display order). VFXView's MoveCategory is controller-
coupled, so the op replicates it at model level: it lazily syncs the
categories list from the params (mirroring VFXViewController) before
moving, since headless set_parameter_category only writes the param's
category string. Describe gains a top-level categories[] oracle
(name/collapsed/order). akiojin#9 Blackboard now complete bar deferred
cross-graph copy-paste.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…jin#11)

designate_template writes the VFX importer's template metadata
(name/category/description + optional icon/thumbnail by path) and the
useAsTemplate flag via the package's official
VFXTemplateHelperInternal.TrySetTemplateStatic, then persists the
importer settings and reimports so the .meta carries the template block.
Describe gains a top-level `template` oracle (read back via
TryGetTemplateStatic; null when not a template). akiojin#11 Templates now
fully complete (sort/favorite stay out-of-scope UI).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ojin#15)

Compose-only proofs over the existing m_HLSLCode/m_ShaderFile ops — the
package HLSLParser already resolves VFXSampler2D→Texture2D and
StructuredBuffer<T>→GraphicsBuffer slots (s_KnownTypes) and #include
directives (s_IncludeParser) when source is set, so no new code is
needed. Adds committed fixture HLSLMain.hlsl (which #includes the
existing HLSLInclude.hlsl) + two EditMode tests asserting the resolved
slot types and clean recompile. akiojin#15 Custom HLSL now complete — clears
the last niche Pass-2 tail box.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…iojin#17)

New top-level tool (sibling of vfx_runtime/vfx_settings) for the SDF Bake
Tool's programmatic path. Uses the package's PUBLIC MeshToSDFBaker
(construct → BakeSDF → read back the 3D SdfTexture RenderTexture → save
as a Texture3D asset). The package's own SaveToAsset is internal and goes
through an interactive SaveFilePanel (headless blocker), so we do our own
AsyncGPUReadback (per-layer, to capture all depth slices) +
AssetDatabase.CreateAsset at the caller's path. Params: meshPath,
outputPath, maxResolution, center/size (default mesh bounds),
signPassCount, threshold, sdfOffset, overwrite. Guards on
SystemInfo.supportsComputeShaders. Full 5-layer: catalog +
host case + handler + EditMode tests (committed Cube.obj fixture; test
Asserts.Ignore without compute) + skill v0.29.0 + docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ed contexts

Block ops (add_block/set_block_setting/set_block_enabled/remove_block/
reorder_block/move_block/duplicate_block) resolved a context only by
contextType, always hitting the first match — so a graph with two same-typed
contexts (e.g. two Spawners across two systems) could not be targeted
unambiguously. Surfaced by the agent-mode eval: a clean-room agent had to
destructively delete+rebuild a Spawner to add a block to the right one.

Add an optional contextIndex (absolute position in the context list) via a
shared ResolveBlockContext helper, threaded through every block op and the
link-node resolver (link_slots/unlink_slots/set_slot_value block/context
endpoints). move_block/duplicate_block also accept toContextIndex for the
destination. contextType stays first-match (back-compat). LocateBlock is now
parameter-based so it honors the index.

5-layer: tool_catalog schema (contextIndex/toContextIndex) + handler +
EditMode test (ApplyAddBlock_ContextIndexTargetsSameTypedSiblingContext;
150/0 green) + skill v0.30.0 (contextIndex + Invocation flags note).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the agent-mode eval that proves an agent can BUILD the right Visual Effect
Graph from a natural-language prompt using ONLY the unity-vfx-graph skill — the
project's real thesis. It is an on-demand DISCOVERY tool (surfacing skill/docs
ergonomics gaps), not a CI gate; the runner always exits 0.

Outcome layer (new): tests/fixtures/vfx-agent-eval/benchmark.jsonl (7 tasks,
each with an NL prompt + a vfx_describe_graph oracle grader) +
scripts/vfx-agent-eval/vfx-agent-eval.sh (runner + embedded Python scorer whose
graders are ported verbatim from the manual proof) + README + an opt-in nightly
workflow gated behind secrets.VFX_AGENT_EVAL_AGENT_CMD (needs a Unity-equipped
runner; skips cleanly when unset). The runner has two modes: --agent-cmd (full
clean-room-agent loop) and probe-only (grade hand-built probes).

Routing layer: 13 VFX rows (SR-128..SR-140) appended to the existing
skill-routing benchmark, covering vfx_describe_graph/list_library/apply/runtime/
settings/bake_sdf incl. the new contextIndex addressing.

Mechanism was validated manually first (clean-room subagent per task, oracle-
graded) — all 7 tasks PASS. See VFX-Graph-LOG.md SD/SD.2 in the project root.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bulletproofing pass: 8 more clean-room agent tasks (VAE-008..015) spanning
capabilities the first 7 didn't touch — Custom HLSL operator, GPU-event chain,
blackboard categories, instancing, custom attributes, flipbook output, sticky
notes, system naming. All 8 oracle-graded PASS (15/15 total). Added the 8 tasks
to tests/fixtures/vfx-agent-eval/benchmark.jsonl and 8 matching graders to the
scorer (ported verbatim from the oracles used to grade the run).

Discovery payoff: the flipbook task surfaced a real SKILL.md bug — it listed
uvMode:"FlipbookBlend", but the live UVMode enum rejects it ("Could not convert
'FlipbookBlend' to UVMode"); frame-blending is the separate flipbookBlendFrames
bool. Fixed the doc to list only "Flipbook" and clarify the blend/motion-vector
bools. Also added a cross-reference on add_parameter noting the blackboard
category lazy-population behavior. Skill v0.31.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… tasks)

Two more clean-room agent tasks (VAE-016 particle strip, VAE-017 mesh output),
both oracle-graded PASS -> 17/17. These were thought to need a new
contextModelType oracle, but describe already surfaces each context's C# class
as contexts[].type, so they grade off that (VFXComposedParticleStripOutput /
VFXMeshOutput). Added 2 graders to the scorer.

Finding (both agents): no convert/swap-context-type op exists — changing a
system's output type means remove_context + add_context + link_flow. Documented
that recipe in SKILL.md plus the four output type class names for verification
(VFXPlanarPrimitiveOutput / VFXComposedParticleStripOutput / VFXMeshOutput /
VFXStaticMeshOutput). Skill v0.32.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the `simulate` runtime op and the runtime eval tier the ROADMAP scoped.

simulate op: vfx_runtime gains `simulate` (params deltaTime=0.05, steps=1) →
VisualEffect.Simulate(float,uint), advancing a live effect's sim headlessly.
5-layer: handler case + tool_catalog schema (deltaTime/steps) + description +
docs/tools.md + skill v0.33.0 + a PlayMode test
(Runtime_SimulateOp_AdvancesSpawnUntilBurstAlive) that drives the op per frame
and asserts a 15-particle burst comes alive (8/8 PlayMode green).

Runtime eval tier: tests/fixtures/vfx-agent-eval/runtime-benchmark.jsonl (3
tasks: set exposed float, set exposed texture, override initialEventName) +
scripts/vfx-agent-eval/vfx-runtime-eval.sh (builds a rig, lets a clean-room
agent drive vfx_runtime, grades vfx_runtime get_state). Validated clean-room:
3/3 PASS. Committed fixture RuntimeRig.vfx (exposed Rate float + Tex texture,
both wired so they survive into the runtime sheet).

Scope: value round-trips are deterministic in the editor (no play mode). SPAWN
behavior (aliveParticleCount>0) needs play mode + Camera + per-frame
simulate-with-yields, so it is graded C#-side by the PlayMode test, not the
raw-driving agent (documented in the skill + README + runtime-checklist).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sync the 78-commit VFX branch onto upstream v0.12.0. Conflicts resolved:

- tool_catalog.rs: keep upstream get_index_status + our 6 vfx_* tools;
  TOOL_NAMES parity count -> 136 (130 upstream + 6 vfx).
- UnityCliBridgeHost.cs: take upstream's router-based dispatch (inline
  command switch removed upstream).
- BridgeCommandRouter.cs: register the 6 vfx_* handlers in the new registry
  (satisfies remote_tools_have_unity_bridge_dispatch_cases).
- docs/tools.md: tool totals -> 136 / 125 runtime / 11 reference
  (satisfies tools_doc_matches_registered_catalog).
- manifest.json + manifest.unity6.json: keep VFX Graph, bump 17.3.0 -> 17.4.0
  to match upstream URP/SRP 17.4.0; Unity editor -> 6000.4.11f1.
- packages-lock.json: reset to upstream's consistent 17.4.0 base; Unity
  re-resolves VFX Graph 17.4.0 on first project open.

Rust gates: cargo fmt clean; tool_catalog 37/37 incl. all 3 new parity
gates. Remaining test/clippy noise is upstream-owned + Windows-only
(reference-cache fixtures, /etc/passwd path, platform-gated imports) and is
green on upstream's Linux CI.

Unity-side validation (EditMode/PlayMode against VFX Graph 17.4 reflection)
pending an open editor on 6000.4.11f1 — handler is reflection-only so any
17.3->17.4 internal-API drift surfaces there as red tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Unity 6000.4.11f1 re-resolved packages-lock.json on first open, adding the
builtin com.unity.visualeffectgraph 17.4.0 entry (consistent with URP/core/
shadergraph 17.4.0). Validated against this resolution: VfxGraphHandlerTests
150/150 EditMode + VfxRuntimePlayModeTests 8/8 PlayMode green — no internal-API
reflection drift from 17.3 -> 17.4.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove the agent-mode outcome eval (scripts/vfx-agent-eval/,
tests/fixtures/vfx-agent-eval/) and its nightly workflow. Upstream has a
routing eval only (tests/fixtures/skill-routing/) — no outcome/agent-mode
harness precedent — so this stays fork-only. The VFX skill-routing rows in
tests/fixtures/skill-routing/benchmark.jsonl (which extend the upstream
benchmark) remain. No vfx_* op, handler, skill, test, or doc is affected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e37d3376-fdef-40c9-a73b-d10e8e63a1da

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@arghhhhh
arghhhhh force-pushed the vfx-graph-control-pr branch from 8b8e7bb to 89fd6dd Compare June 25, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants