-
-
Notifications
You must be signed in to change notification settings - Fork 70
Changelog
Action count is approximate. ~1,400+ actions across 24 in-tree namespaces — query
monolith_discover()for the live figure.
A reliability release: the project index now survives a crash instead of starting over, several read actions that were quietly answering with the wrong object are fixed, and monolith_discover can finally search across namespaces. Thanks to @kunkunGames, @DanaFo, @Hvizeu, @aggitti, @nanbarada, and @Thomasbehan for the reports.
-
Animation layers can be authored without an interface asset. New
animation add_anim_layer_graphcreates an ABP-native animation layer — aUAnimationGraphon the animation graph schema in the Animation Blueprint's own function graphs, which is what the editor's My Blueprint → + → Animation Layer button produces. The layer belongs to the ABP, so variant ABPs no longer have to share aUAnimLayerInterfacesignature just to have a layer. The schema is the load-bearing part: it is what makes the animation compiler emit a realFAnimBlueprintFunction, whichblueprint add_functioncannot do — it produces an inert K2 graph. The Output Pose root node is created automatically. Optionalinput_posesdeclares input pose pins by name (capped at 16). Refuses a duplicate graph name outright instead of renaming the incumbent, plus the reserved nameAnimGraph, child Animation Blueprints, macro libraries, and interface Blueprints. -
monolith_discovercan search every namespace at once. Afilterpassed without anamespaceused to be silently ignored — you got the plain namespace inventory back and had to walk all of them by hand. It now searches the whole registry, tags each row with its owning namespace, and reportsmatched_namespacesbefore pagination so "which namespace owns this" stays answerable even when rows are capped. An absentlimitcaps at 50 here (the whole registry is a much bigger haystack than one namespace);limit: 0still means all. Thanks @kunkunGames (#112). -
risk get_mining_statussays why a risk query came back empty. Reports which repositories were mined, which candidates were rejected and why, whether mining ran this session, and the row counts of the four risk tables. The git-backedriskactions also attach adiagnosticsblock when they return nothing, with a hint naming the setting to change. -
project get_statsreports assets skipped by deep indexing —skipped_assetsandskipped_asset_paths(up to 50), populated when the index dropped an asset after repeated interrupted attempts. -
Monolith.StartIndex force— the console command takes an optionalforceargument. BareMonolith.StartIndexresumes an interrupted index;forcewipes and starts over.
-
An interrupted full index no longer throws away the work it already did. A full index wiped the database up front and wrote its completion marker only at the very end, so any crash or kill left no marker and the next launch erased every batch the previous run had finished. On a large project one crash cost hours. The index now checkpoints per asset, resumes on the next launch, and drops (never silently) an asset that twice crashed the editor mid-index. Recover with
Monolith.StartIndex force. Thanks @Hvizeu (#117, #120). - A project with fewer than 500 assets no longer re-indexes from scratch on every launch.
-
Blueprint component reads returned the C++ parent's defaults, presented as your Blueprint's values.
get_component_detailsandget_componentsread the native parent's class-default object whileset_component_propertywrote the Blueprint's own — so on any Character Blueprint a capsule half-height overridden to 96 read back 88, and the same applied to transforms, collision, movement settings and mesh/anim-class wiring. Both reads now use the Blueprint's own CDO through one shared resolver.get_component_detailsalso reportssource,resolved_componentand anote;get_componentsgainsinherited_components[]. Thanks @DanaFo (#116). -
The
Meshalias resolved to the capsule on Character Blueprints. Aliases now carry their own target class, an exact component name always beats an alias, and an ambiguous alias reports the candidates instead of picking the first. Thanks @DanaFo (#116). -
set_component_propertycan now write a component inherited from a parent Blueprint, by creating an Inheritable Component Handler override on the child instead of failing with "component not found". Thanks @Thomasbehan (#102). -
Enum widget variables compile to enum properties instead of
int.ui add_widget_variablebuiltenum:<Name>pins with a type-picker category that is never valid on a real pin, so the variable fell through to anintproperty and every Get/Set node refused a real enum connection. The tell was a "not compatible" message naming a spaced enum (ESlate Visibility Enum). Already-broken assets are repairable in place withblueprint set_variable_type. Thanks @aggitti (#115). -
enum:accepts a full object path.enum:/Script/UMG.ESlateVisibilitynever resolved on any action, on any version — lookup flattened the whole argument into a single name, so a path could only ever miss. -
The
risknamespace mined no repositories on almost every project. The git roots were a hardcoded list of nested-plugin paths that never probed the project root, so for anyone whose project root is the git repository — the ordinary layout —risk_queryreturned empty permanently with nothing to say why. Roots are now discovered at runtime, with two new settings under Editor Preferences → Plugins → Monolith Reflection Intel → Risk. Thanks @nanbarada (#119). -
Hotspot scores were
0for every file, because churn paths and complexity paths were keyed in different path spaces and never met. Existing risk tables rebuild once on the first query after upgrading. - Editing a risk setting did nothing until the editor was restarted.
-
project searchno longer reports query errors as zero results. A malformed FTS5 query came back as a successful empty result set, indistinguishable from a genuine no-match. Caller errors are now-32602and storage failures-32603, withLIMITbound as a parameter. A column filter naming an unknown column now names it and lists the valid ones. Thanks @kunkunGames (#113). -
Corrected the documented
NEARsyntax and scope forproject search— the working form isNEAR(BP_Enemy Health, 3), and the index covers asset and graph-node fields, not variables and parameters. -
monolith_discoverpagination no longer overflows into an empty page with a negativenext_offseton a very largelimit. Thanks @kunkunGames (#112). -
Stopping or restarting the Monolith server no longer takes every other plugin's HTTP routes down with it. Teardown called a process-wide stop, so Web Remote Control, PerfCounters and anything else holding a route lost service whenever Monolith restarted. Monolith now unbinds only its own six routes. One consequence: the listener survives
Stop(), so a TCP probe of port 9316 is no longer a valid liveness check — usemonolith_status. Thanks @kunkunGames (#114). - Closing the editor during a project index could crash on shutdown, via game-thread callbacks that outlived the task object they captured.
- A failed project index left the asset index silently stale for the rest of the session — the live Asset Registry callbacks were re-armed only on success, so after a failure every later asset change was dropped until a reindex or restart.
- A reindex that never started no longer reports success, and an indexer that failed to start no longer refuses every request afterwards until the editor is restarted.
- Editor startup no longer stalls on the port probe — the bind check used a blocking socket, costing roughly two seconds on the game thread per retry on Windows.
- The animation indexing pass commits per batch instead of once at the end, and a failed database reset now aborts the index instead of being ignored.
-
animation set_anim_graph_node_propertyno longer writes to a different node when its scope fails to resolve.graph_name/state_namewere advisory: an unresolved scope fell through to an all-graphs search bynode_id, and node ids are not unique across graphs — so the write landed in an unrelated animation layer, and the asset still compiled and still validated, it just played the wrong animation. A supplied scope is now authoritative. The resolver also reaches nested state machines at any depth.
-
animation add_linked_anim_layernow finds ABP-native layers too. When no implementedUAnimLayerInterfacedeclares the requestedlayer_name, the action looks for a layer graph on the Animation Blueprint itself and binds it as a self layer — mirroring the engine, which stores no "is self" flag and treats a failed interface lookup as the self signal. Interface layers still win when the name exists in both places, passinginterface_classdisables the native fallback, andinstance_classis rejected for a self layer. A self bind reportsinterface_class: "<self>"andguid_resolved: false. - Ordering note: a self layer's pose pins resolve against the Animation Blueprint's generated skeleton class, so creating a layer with
compile: falseand immediately placing its node yields a node with no pose pins. Keep the defaultcompile: true, or recompile before placing. -
animation set_anim_graph_node_propertyreports where the write landed, viaresolved_graph_path— the root-to-leaf graph path of the node actually written. -
Pin-type strings are parsed strictly by the actions that create pins. A typo'd
typeinblueprint set_function_paramsused to produce aboolpin, and an unresolvableenum:Whateverproduced a variable with no type object at all. Both now return an error naming the token and the reason, and the signature-rewriting actions validate every type before touching a single pin, so a rejected call leaves the existing signature untouched. -
blueprint get_inherited_component_overridereports a wider set ofsourcevalues —scs,cdo_native,ich_override,inherited_scs,parent_cdo_fallback. Callers matching on the literal"ich"need updating. -
project searchvalidates its parameters before touching the index —queryis trimmed, must be non-empty and is capped at 4096 characters;limitis clamped to 1-1000. - The Project Settings re-index button is greyed out when the index database is closed, instead of being enabled and doing nothing.
-
Monolith.StartIndexresumes rather than wipes. UseMonolith.StartIndex forcefor the old behaviour;monolith_reindex force=trueis unchanged.
- Three release gates that reported green while the path they defend was open are now real: the offline CLI build gate (a
cmd.exevariable-expansion bug made its failure branch unreachable, so a failed compile published a stalemonolith_query.exeand exited 0), the offline-exe freshness guard (documented but invoked by no script), and the pre-v2 SHA marker detector (anchored more narrowly than the deployed parser it defends). See Auto-Updater for why the marker names matter.
Action count is approximate. ~1,500+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
This release closes out the open pull-request queue. Thanks to @Thomasbehan, @whalemenace, and @kunkunGames for the reports.
-
niagara get_module_graphcan emit link topology. Passlinks: truefor a top-leveledgesarray plus apin_idon every pin, so branch tracing through static switches no longer requires a T3D export. Output is unchanged when the flag is absent; edges are keyed by the(node_guid, pin_id)pair, since pin IDs alone are not unique within a graph. Thanks @whalemenace (#109).
-
ui set_widget_propertycan now set Margin and Vector4 properties.valuewas declared as a string, so every documented shape arrived as text and was rejected — while the error message listed those exact shapes as valid. Thanks @Thomasbehan (#110). -
Malformed destination paths are rejected before anything is created, across seventeen actions in
blueprint,material, andniagara. In the compound PBR workflow, a bad option or an existing-material collision now fails before the first texture import. Thanks @kunkunGames (#106, #107, #108). - Material creation no longer risks overwriting a
.uassetthat is on disk but not yet in the Asset Registry. - A spurious
LogEditorAssetSubsystem: Erroron every successful asset creation is gone.
-
Paths containing characters Unreal forbids in a package name are now errors —
\ : * ? " < > | ' <space> , . & ! ~ @ #. Previously they passed a weaker check and produced a mangled asset. If a path you rely on is rejected, please open an issue rather than working around it. -
Object-path destinations such as
/Game/Foo/M_Bar.M_Barare accepted and normalised, since the forbidden set includes.and that form is what you get copying a path out of a search result. -
blueprint seed_data_assetwithdry_run: truereports a malformed path as an error rather than returning a dry-run report.
Action count is approximate. ~1,500+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
-
blueprintwildcard array pins now resolve — tool-createdArray_*nodes spawn the palette-correctUK2Node_CallFunctionsubclass, so their wildcard pins take a type from your connections; the schema-mediated disconnect path resets wildcard pins. Thanks @Alexbeav (#95). -
blueprintreference-audit blind spots closed —list_graphs/search_nodes/find_variable_references/get_graph_datanow see collapsed-composite subgraphs, input-pin default values, string-bound timer callers, and inherited-scope variables; nested graphs are classified via a shared helper. Thanks @Alexbeav (#96). -
blueprintlocal-variable data pins materialize —VariableGet/VariableSetnodes for locals now bind viaSetLocalMemberwhen the graph declares a matching local. Thanks @Alexbeav (#97). -
blueprintenum member variables are enum-typed —VariableGet/VariableSetnodes now use the schema's byte + subobject convention, so their pins connect to enum consumers. Thanks @Alexbeav (#98). -
UE 5.8 / Linux source-build compatibility — build fixes for the 5.8
FJsonObjectshared-string keys and new-Werrorsites, plus Reflection Intelligence support for the 5.8 UHT codegen format (replicated properties, RPCs,OnRep, interfaces, parent chains). Thanks @gregorygmwhite (#99). -
MetaSound build error on UE 5.8 — fixed the 5.8 MetaSound compile break, plus broader cross-version hardening of
FJsonObjectkey iteration (GAS / LogicDriver / ComboGraph bulk-fill and MetaSound) via theMonolithKeyToStringhelper. Reported by @Matt-Makes (#100).
-
blueprintfind_variable_referencesdefaultsinclude_inheritedtotrue(wasfalse) — a deletion audit over-reports rather than returning a false zero for parent-class variables. Passinclude_inherited: falsefor the strict own-class view. Thanks @Alexbeav (#96).
Action count is approximate. ~1,500+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
-
CRITICAL — auto-updater no longer crashes the editor on Install (Windows) (#90, #94). The integrity check added in v0.14.7 called
FPlatformMisc::GetSHA256Signature, which has no Windows implementation — the engine's generic fallback is a fatal assert, so clicking Install killed the editor whenever the target release carried a checksum marker. The updater now uses a portable, NIST-vector-tested SHA-256. Release-note checksum markers moved to newMonolith-SHA256-v2-*names so pre-fix updaters fail safe (a "missing integrity marker" notification on 0.20.3+, an unverified-but-working install on older versions) instead of crashing — see Auto-Updater. Thanks @Alexbeav (#90, #91) and @SilkroadLabs (#94). -
blueprintadd_event_dispatchercreates the multicast delegate member variable, soCallDelegate/AddDelegate/RemoveDelegatecan bind the dispatcher;remove_event_dispatchercleans it up. Thanks @Alexbeav (#84). -
blueprintadd_node/resolve_nodeno longer crash the editor onnode_type: "SpawnActor"(legacy-node title null-deref); generic-fallback nodes report a safe title. Thanks @Alexbeav (#85). -
blueprintadd_timeline_track— the new track's output pin now actually appears on the timeline node (display-track registration + node reconstruction). Thanks @Alexbeav (#86). -
blueprintbatch_executehonors a top-levelgraph_namedefault for all ops. Thanks @Alexbeav (#87). -
blueprintresolve_nodedelegate-node dry-runs resolve real signature pins. Thanks @Alexbeav (#92). -
String-encoded array/object params recovered centrally — MCP clients that serialize complex arguments to JSON strings no longer hit "array is required" errors on
delete_assets,save_packages,set_function_params, and friends. Thanks @Alexbeav (#93).
-
editorload_levelfail-closed guards — refuses on a dirty current map (override withdirty_policy:"discard") and on a stale rooted in-memory copy of the target world, instead of silent data loss or a fatal engine assert. Thanks @Alexbeav (#89). -
Paired
MODAL_OPEN/MODAL_CLOSElog telemetry with window identity + slow-task flag on UE 5.8+. Thanks @Alexbeav (#88).
Action count is approximate. ~1,500+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
Ergonomics upgrades to the ui and blueprint action packs from the Ideas board (Discussion #74, thanks @k-s-s). No new actions — existing ones just got easier to call.
-
uiadd_widgetacceptsparentas an alias forparent_name, so you can drop a widget into a non-root panel directly. -
uiset_widget_propertynow allowlists commonUWidgetproperties by default (Visibility,RenderOpacity,ToolTipText,bIsEnabled,RenderTransform.Angle/.Scale/.Translation) — no moreraw_mode=truefor the everyday ones. -
uiset_brushmakesproperty_nameoptional (auto-resolves Image →Brush, Border →Background) and takescoloras an alias fortint_color. -
uiset_slot_propertysupports grid slots (row,column,row_span,column_spanonUUniformGridSlotandUGridSlot). -
blueprintdescribe_cdo_schemaemits the correct positionalTMapImportText hint, including the struct literal for struct-valued maps. -
blueprintadd_variable/set_variable_typeaccept prefixed key and value types in map strings (e.g.map:enum:ESlateVisibility:struct:LinearColor), so enum-keyed and struct-valued maps are authorable. -
blueprintconnect_pinsdisambiguates node IDs that exist in multiple graphs and tells you to passgraph_name. -
blueprintadd_node/resolve_noderesolve user-defined enums onK2Node_SwitchEnum(short name,/Scriptpath, or unloaded asset; plusenum/enum_pathaliases) and Blueprint-defined functions onK2Node_CallFunction(self and external Blueprints).
Issue #82 (deferred MCP context loading) was already handled in v0.20.3 by terse-by-default
monolith_discover+describe_query— nothing new needed. Thanks @aggitti.
-
BlueprintAssist bridge vs. BA 4.9.0+ —
MonolithBABridgeno longer C2039s against BlueprintAssist 4.9.0+ (RequestFormatAll/GetNumberOfPendingNodesToCachechanged);__has_includekeeps pre-4.9 building too. PR #78 — thanks @tc-imba (parallel fix @mewliks, #76). -
GeometryScripting delay-load DLLs gated to Win64 — fixes
BuildEnvironment.Uniqueand the macOS source link. PR #77 — thanks @itismyfield. -
UE 5.8 source builds —
FJsonObjectkeys are now routed through aMonolithKeyToStringshim (they becameFSharedStringin 5.8), so the sameMonolithAnimationsource compiles on 5.7 and 5.8. Issue #80 — thanks @Baba-Ramsi (also @dulanw, #79). -
Linux / clang builds — removed nested
/*in doc comments that tripped-Werror,-Wcommentat fourMonolithReflectionIntelsites. Issue #83 — thanks @daschatten-tb. -
Indexer data-loss guard — the source indexer no longer strips
RF_Standalonefrom assets that were already loaded and referenced; a load-time residency gate across sevenTryUnloadPackagesites (plus the landscape cleanup branch) means it only unloads packages it brought in. Issue #81 — thanks @Alexbeav. -
Optional-plugin detection no longer false-positives on plugins that share a name prefix (e.g.
BlueprintRetargetbeing read as BlueprintAssist). Disk-presence globs now match full plugin names. Reported by @k-s-s (#66).
Action count is approximate. ~1,500+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
-
Dual-engine releases — per-engine prebuilt zips for UE 5.7 and UE 5.8. Each release now ships one flat plugin zip per Unreal Engine version (
Monolith-vX.Y.Z-UE5.7.zip,Monolith-vX.Y.Z-UE5.8.zip), plus a legacyMonolith-vX.Y.Z.zip(the 5.7 build) for older auto-updaters. Download the zip matching your engine; a prebuilt binary is locked to one engine's ABI, so 5.7 and 5.8 builds are not interchangeable (source builds work on both). The auto-updater is now engine-aware — it detects the running engine, downloads the matching zip, verifies it against a per-engineMonolith-SHA256-UE5.x:checksum, and refuses to install if no build exists for your engine. -
monolith_discoveris terse by default — major token reduction. A per-namespacediscover(namespace)now returns each action's name plus a one-line description (first sentence, else hard-capped at 150 chars on a word boundary with a...suffix), instead of the full per-action param JSON-Schema. This cuts roughly 70-84% of the tokens on the heavy namespaces (e.g.blueprint) and about 77% overall across all 26 namespaces, verified universal. Full param schemas are still available two ways: the existingdescribe_query("action_schema")returns a single action's full schema (~54 tokens) on demand, and a newdetail=true(aliasverbose=true) param ondiscoverreproduces the pre-change shape inline. Newdiscoverparams:filter(case-insensitive substring on action name OR full description),offset(default 0), andlimit(default 0 = ALL; pagination is opt-in — the default still returns the COMPLETE list). The response carriestotalalways,next_offsetonly when a positivelimitleaves more remaining, and aschema_hintin terse mode. Backward-compatible:discover(ns, detail=true)is byte-for-byte the old output, and fulldiscover()with no namespace is unchanged.
Action count is approximate. ~1,500+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
-
From-source rebuilds still hard-linked optional plugins MonolithAI couldn't load without. v0.20.1 rebuilt the shipped release binaries clean, but it didn't fix the source path — so anyone who rebuilt Monolith from source on a stock engine kept hitting the same
GetLastError 126load failure onMonolithAI.dll. The root cause: the optional-plugin gates inMonolithAI,MonolithMesh,MonolithIndex,MonolithAudio, andMonolithAnimationonly checked whether a plugin was present on disk. Engine plugins like MassSpawner / ZoneGraph are always on disk, so the gates linked them in even when they weren't enabled in the project, and a stock engine doesn't load them at runtime. Those fiveBuild.csfiles now read the.uprojectProjectDescriptor and gate on whether the plugin is actually enabled in the project, not merely present. A from-source build with those plugins disabled now produces aMonolithAI.dllwith zero MassSpawner / ZoneGraph imports; builds that do enable them keep the features. This is the source-side complement to v0.20.1's binary fix. (#71, reported by @aggitti)
- Dropped
GameplayAbilitiesfrom the release import-leak sentinel list — it's a hard dep inMonolith.uplugin(auto-enable contract guarantees load order), so it's functionally safe to hard-link and was triggering a false-positive ship block.
Action count is approximate. ~1,500+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
-
MonolithAI failed to load on stock UE 5.7.4 (Epic Launcher) with
GetLastError 126. The v0.20.0 release binary hard-linked the optionalMassSpawner(MassEntity / MassGameplay) andZoneGraphplugin DLLs, which aren't enabled in a stock engine build, so on a clean install the plugin could not load. The release binary is now correctly gated and MonolithAI loads without those experimental plugins. (#71, reported by @aggitti)
Action count is approximate. ~1,500+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
-
Blend space baking + interpolation control (
animation). Two new actions for getting blend spaces runtime-correct.-
bake_blend_space— rebuild a blend space's triangulation (FBlendSpaceData) viaResampleData()and mark it dirty, for blend spaces authored externally or before this release's auto-bake fix. Params:asset_path. Returnshas_blendspace_data,sample_count,baked, and awarningwhen a 2D blend space has fewer than 3 samples (triangulation needs at least 3). Works on 1D and 2D blend spaces. -
set_blend_space_interpolation— set a blend space's input-interpolation settings, then resample + dirty.use_gridtogglesbInterpolateUsingGrid(true = runtime uses the grid, false = the triangulation);preferred_triangulation_directionchooses the edge direction (None/Tangential/Radial). Returns the resulting flags includinghas_blendspace_data. In grid mode the triangulation is intentionally empty, sohas_blendspace_dataisfalse— that is correct, not a failure.
-
-
State machine editing — remove states, remove transitions, re-point the entry (
animation). Three new actions completing the anim-blueprint state-machine authoring surface. Previously you could create states and transitions and set the entry only at creation time; now you can edit a state machine after the fact.-
remove_anim_state— remove a state from a state machine and tear down its inner anim graph. Params:asset_path,machine_name,state_name, andremove_dependent_transitions(defaulttrue, also removes transitions that referenced the state). Refuses to remove the state machine's current entry state — re-point the entry withset_anim_entry_statefirst, then remove. -
set_anim_entry_state— re-point a state machine's Entry node at an existing state. Params:asset_path,machine_name,state_name. Returns the previous entry target, and reportsunchangedwhen the named state is already the entry. -
remove_anim_transition— remove the transition from one state to another. Params:asset_path,machine_name,from_state,to_state. Reports how many matching transitions were removed.
-
-
Remove an IK Rig solver (
animation).remove_ik_solverremoves a solver from an IK Rig's solver stack by index. Params:asset_path,solver_index(0-based). Validates the index against the current solver count — an out-of-range index returns a clear error naming the valid range — and reportsremoved_indexandsolver_count_after. -
AnimGraph-authoring pack (
animation) — 14 new actions. Pose-composition, slot, cached-pose, output-wiring, blend, sync, layered-blend, Control Rig, and linked-layer anim-graph node authoring, composing with the existingadd_anim_graph_node/connect_anim_graph_pinswrite surface:add_apply_additive,add_apply_mesh_space_additive(Apply Additive / mesh-space additive nodes),add_slot_node(slot name validated against the skeleton's slot groups),add_save_cached_pose/add_use_cached_pose(paired bycache_name),set_output_pose_source(wire a node into the AnimGraph Output / Root result pin),set_state_result_source(wire a node into a state machine state's result pin),add_blend_by_int(grown tonum_posespins),add_blend_by_enum(Blend Poses by Enum bound to aUEnumviaenum_path; one pose pin per exposed enumerator plus a Default/else pin, skipping the auto_MAXsentinel andHiddenenumerators),set_sync_group(player node sync group name / role / method),set_layered_blend_bones(per-bone branch filters on a Layered Blend Per Bone node),add_anim_control_rig_node(control_rig_class; IO pins regenerate),add_linked_anim_layer(layer_name, optionalinterface_class),add_conduit(a state-machine conduit whose bound graph is a transition-logic graph, not an anim graph). -
set_anim_node_pin_bindingbootstraps the binding object (animation). It now constructs a node's binding object when it has none, so it works on previously-unbound AnimGraph nodes instead of refusing them. -
auto_layoutbuilt-in formatter (animation). A newformatter:"builtin"(also the"auto"fallback) lays out anim graphs by dependency-aware layering WITHOUT Blueprint Assist, so layout works in release builds where Blueprint Assist is compiled out. -
set_transition_rulegains anexpressionkind (animation). Compound multi-term transition conditions, extending the existingbool/auto/comparekinds:terms: [{ lhs, op, rhs, abs?, negate? }]combined withcombine: "and" | "or". Each term builds one comparison sub-node — optional per-termabswraps the left-hand side, optional per-termnegateinverts the term result — and all terms fold through Boolean AND/OR into the transition result.get_transition_ruledecodes it back.
-
MCP-authored blend spaces played bind/A-pose at runtime (
animation). The four blend space mutators —add_blendspace_sample,edit_blendspace_sample,delete_blendspace_sample,set_blend_space_axis— mutated samples without rebuilding the triangulation (FBlendSpaceData), so a blend space authored over MCP shipped with empty triangulation and evaluated to the bind/reference pose at runtime. The asset-editor preview recomputed the triangulation live, which masked the problem in-editor. Each of the four actions now callsResampleData()after the edit and marks the package dirty, so every sample/axis change re-bakes correctly. Existing broken blend spaces can be repaired in place with the newbake_blend_spaceaction. -
add_ik_solverfailed to add solvers, Full Body IK especially (animation). The action resolved the solver type through a hardcoded reflected struct path that does not resolve in UE 5.7, so the add silently failed.solver_typeis now resolved against the live solver-struct table the engine registers — a friendly alias (fullbodyik/fbik,limb,pole,bodymover,settransform,stretchlimb) or the exact struct name, falling back to a unique substring; an ambiguous value returns the candidate solvers and an unknown value returns the available list. Solvers, including Full Body IK, now add correctly.
Action count is approximate. ~1,400+ actions across 25+ in-tree namespaces — query
monolith_discover()for the live figure.
An LLM-C++-ergonomics release: an eight-action source pack so your AI resolves an include, signature, deprecation, Build.cs deps, header lint, or a UCLASS stub in one round-trip, plus a parser fix that tripled the engine source index. On top: live-PIE introspection + driving (editor), anim-node binding read/write and time-series PIE sampling (animation), Blueprint variable census + contract reconciliation (blueprint), and T3D asset-text export (project). Two first-launch crash/load fixes (issue #70, thanks @aggitti) and a ~40% smaller tools/list manifest round it out.
-
LLM C++ authoring ergonomics (
source) — 8 actions across three phases. Read-only, offline-served lookups so an agent resolves an include, signature, or deprecation in one round-trip instead of reading raw source.-
Phase 1:
get_include_path(canonical#includefor a symbol, withincludable+ owning module +build_cs_note),get_signature(exact overload signature(s), inline bodies/macro continuations stripped),check_deprecations(batchUE_DEPRECATEDstatus; returnsindex_state:"empty"before the first reindex rather than a false clean bill). Adds asymbol_deprecationsindex (schema v1→v2) populated on the next fulltrigger_reindex, plus amodules.build_cs_pathbackfill. -
Phase 2:
verify_symbols(batch pre-flight — existence + include + signature + deprecation per symbol),find_example_usage(ranked real call-site examples via source-line FTS,preferengine/project, cursor-paginated),suggest_build_cs_deps(required + missing Build.cs deps for a file or symbol list; reads the module's Build.cs from disk so it works on uncommitted files). -
Phase 3:
lint_header(regex-level UHT-gotcha lint that works on unindexed headers you just wrote),generate_class_stub(UCLASS-derived.h/.cpppair returned as TEXT — never writes to disk), andeditor.get_build_errorsgains an additive deterministicfix_hints[]array (LNK2019onZ_Construct_*/UDeveloperSettings,C4996deprecation,generated.h-must-be-last).
-
Phase 1:
-
Live-PIE object read/call + driving (
editor).pie_get_object_properties(read UPROPERTY values off a resolved PIE object by dotted, UDS-friendly path — read-only),pie_call_function(call a BlueprintCallable function/event on it — mutates live PIE state, rejects replicated/latent),pie_set_control_rotation(with best-efforthold_frames),pie_inject_input_action(Enhanced Input injection with shape-mapped values),pie_possess_spectator_free(free-fly spectator toggle). Adds an always-enabledEnhancedInputBuild.cs dep — release-build safe, noWITH_*gate. -
Stat-group counter readout (
editor).get_stat_group_valuesreads a stats group (STATGROUP_Animor shortAnim) into a structured response — counter values + cycle-stat timing in ms;sample_frames>1aggregates min/avg/max.#if STATS-gated (Development editor only, not Shipping/Test). -
Anim-node function + pin bindings read/write (
animation).get/set_anim_node_function_bindings(the per-node On Initial Update / On Become Relevant / On Update function slots, with the engine's thread-safe + signature validation on write),get/set_anim_node_pin_binding(s)(the per-pin property-access bindings).get_nodesalso emits compact additivebindings/pin_bindingsper node. -
Time-series PIE sampling (
animation).sample_pie_timeseries— an async PIE session that samples a target's dotted, UDS-friendly variables each tick and fires typed provocations (set_control_rotation/add_movement_input/jump/console_command) on a timeline. Poll withpoll_pie_smoke, force-end withstop_pie_smoke. Plus acompare_to_actorlockstep parity option onsample_pie_anim_instance. -
Variable reference census + contract reconciliation (
blueprint).find_variable_referencesfinds every graph node that reads or writes a member variable (incl. thread-safe Property Access nodes), classifying each as read/write/other.compare_class_variable_contractandpromote_variables_to_parentreconcile a Blueprint's local variables against a native parent during nativization. -
First-class asset text (T3D) export (
project).export_asset_textexports an asset to its native T3D text dump (or grepped excerpts) and returns it directly — the escape hatch for surfaces no typed read exposes. Scope withobject_filter/grep_pattern, bounded bymax_bytes.
-
tools/listmanifest ~40% smaller — duplicated action list dropped from dispatcher descriptions. Each domain dispatcher (source_query,material_query, etc.) previously inlined its full"Available actions: a, b, c..."list into the tooldescriptionfield — a copy of names already carried authoritatively by theactionenum in the schema. The prose join is gone; the description now points clients atmonolith_discover("<namespace>").tools/listdrops from ~77.8K to ~46.7K bytes (~16k tokens) with no capability loss. Theactionenum is unchanged — no dispatch behaviour changes.
-
MonolithMesh first-launch load failure — GeometryScripting DLLs now delay-loaded (
mesh, issue #70, thanks @aggitti). On a clean build,MonolithMesh.dllcarried a load-time hard import onUnrealEditor-GeometryScriptingCore.dll(+ GeometryFramework / GeometryCore), surfacing asCouldNotBeLoadedByOS(LoadLibrarynull,GetLastError=126) on first editor launch and failing the whole Monolith plugin load. The three GeometryScripting module DLLs are now inPublicDelayLoadDLLs, so the Windows loader binds them lazily on first Tier-5 call instead of at module load. The full Tier-5 (WITH_GEOMETRYSCRIPT=1) mesh-op surface is preserved, and the.upluginPlugins array is unchanged — no new mandatory dependency. -
Deep indexer no longer asserts on UserDefinedStruct fields with unresolved types (
source, issue #70, thanks @aggitti). The deep indexer calledFProperty::GetCPPType()unconditionally on every UserDefinedStruct field. For a field whose inner type can't resolve — e.g. aTSubclassOf<X>pointing at a deleted Blueprint, which leavesMetaClassnull —GetCPPType()asserted and took the editor down mid-index. ASafeGetCPPType()helper now null-checks the inner type pointer and returns<unresolved>for broken fields instead of asserting; well-formed fields are unaffected. -
Plain-class indexing gap — allman-brace classes/structs now indexed (
source). The non-reflected class/struct extractor required the opening{on the declaration line, but Epic's coding standard puts it on the next line (allman), which structurally excluded most exported non-reflected engine types (FCollisionShape,FSceneView,FScopeLock,FPaths,FRegexPattern, and ~40K others). The parser now accepts the allman brace. Enginesymbolsrows went ~301K → ~967K after a full reindex; existingEngineSource.dbfiles enrich on the nexttrigger_reindex. The fix also hardened the member extractor against two latent crash classes it exposed.
A motion-matching-focused release. A from-scratch Motion Matching authoring pack across the animation, chooser, and blueprint namespaces — Pose Search schema / database primitives, mirror data tables, chooser-table authoring, the AnimBP motion-matching graph, foot-IK, thread-safe AnimBP authoring (Property Access, thread-safe function flag, chooser-database-via-threadsafe), character/actor scaffolding, and a retarget create/run pack. Plus a PIE / profiling harness (async PIE-smoke sessions, CSV/Insights profiling brackets, clip + anim-frame capture, map authoring, nav rebuild/validate), state-machine authoring + live anim telemetry, a generic AI controller that runs a BehaviorTree on possess with movement-driving BT task classes, inherited-native-component inspection, and live DataAsset field read-back.
Action count is approximate. The surface is too large to track to the unit — 1,400+ actions across 25+ in-tree namespaces (public, in-tree only). Query
monolith_discover()for the exact live figure.
Authoritative per-namespace breakdown lives in Docs/SPEC_CORE.md §12.
Niagara HLSL direct-editing plus a round of build + reliability fixes.
Public in-tree action count is approximate — 1,400+ actions across 25+ in-tree namespaces (query monolith_discover() for the live figure). The niagara namespace gained a net +9 this release (issue #64 Tranche 2 search & discovery +7, PR #65 HLSL +2). The editor.delete_assets hardening below adds no new action — it's a new param on an existing action; issue #64 Tranche 1's Blueprint-callable surface adds zero dispatcher actions.
-
Niagara HLSL direct-editing + simulation-stage / event-handler authoring (PR #65, by @middle233). Two net-new
niagaraactions plus a set of module-stack / script / event enhancements:-
get_custom_hlsl_text— reads the HLSL source from aCustomHlslnode via public UPROPERTY reflection. Params:script_path(required), optionalnode_guidto disambiguate multi-node scripts. -
set_custom_hlsl_text— overwrites aCustomHlslnode's HLSL source under aModify()+ transaction with a recompile. Params:script_path(required),hlsl(required), optionalnode_guid. -
Selector-based stage targeting.
get_ordered_modules/add_module/move_module/duplicate_modulenow acceptusage: "particle_simulation_stage"(selectorsusage_id/stage_name/stage_index) andusage: "particle_event"(selectorsusage_id/handler_index), so you can target shared-graph simulation-stage and event scripts directly. -
add_simulation_stagenow materializes the matchingparticle_simulation_stageoutput node and returnsusage_id,stage_id,graph_outputs. -
add_event_handlernow returnshandler_index+usage_id+usageand rejects unresolved inter-emitter source emitters instead of silently creating an emptySourceEmitterID. -
create_module_from_hlslnow generates a ParameterMap bridge graph (InputMap → ParameterMapGet → CustomHlsl → ParameterMapSet → OutputNode), preserves Data-Interface input types (NeighborGrid3D / Grid3D / ParticleRead), and strictly validates HLSL input/output types — unknown types now hard-fail instead of silently degrading tofloat. - See
Docs/NIAGARA_HLSL_GUIDE.mdfor the full HLSL workflow.
-
-
Niagara search & discovery pack — +7 actions (issue #64 Tranche 2).
search_by_parameter,search_by_data_interface,search_by_material,query_niagara(deterministic structured-filter DSL —emitters>N,sim_target=GPU,has_renderer=<name>),find_similar_systems(structural-similarity ranking),find_niagara_references(IAssetRegistry::GetReferencers), andlist_system_data_interfaces(data interfaces actually used by a system). All read-only. -
Blueprint-callable Niagara inspection/search surface —
UMonolithNiagaraQueryLibrary(issue #64 Tranche 1). An editor-onlyUBlueprintFunctionLibraryexposing the read-onlyniagaradispatcher actions as Blueprint-callable nodes for Blueprint utilities and Editor Utility Widgets (24 nodes total — 17 Tranche 1 wrappers + 7 Tranche 2 wrappers). Zero new dispatcher actions, zero cost in packaged / runtime builds (the module is editor-only).
-
editor.delete_assetscould pop a blocking modal and freeze the editor. Deleting an asset that was open in an editor tab, or still referenced, would raise a Slate "asset in use" / "save changes" dialog — which hangs an unattended MCP session because no human is there to dismiss it. The action now closes any open asset editor and clears the package dirty flag for each target before deleting, and runs the delete inside an unattended-script guard so the engine never raises a blocking dialog. A new optionalforcebool (defaultfalse) selects the path:force=falsesoft-deletes after closing editors;force=truecallsForceDeleteObjects, nulling referencers. Per-asset failures are reported in afailed_to_deletearray instead of aborting the whole call. Native C++ — no Python required. Known limitation: a NiagaraScript created and compiled in the same session can't be deleted until its compile state clears (a transient compilation graph holds a reference — the engine's own Content Browser hits the same wall); it becomes deletable after the state clears, e.g. on editor restart. -
From-scratch unity editor builds failed to compile due to duplicated file-local helpers colliding across
.cpps in the same module inMonolithReflectionIntel,MonolithNiagara,MonolithGAS, andMonolithBlueprint. UE adaptive unity concatenates same-module.cppinto one translation unit, so these internal-linkage symbols clashed (C2084/C2011/C2668). Masked from releases by-DisableUnityand masked locally because adaptive unity excludes recently-edited files — so it only bit fresh-clone / full-unity (end-user first-compile) builds. Helpers are now unity-safe (hoisted shared units + file-unique names); behaviour-preserving, no API change. A new full-unity collision gate inmake_release.ps1guards against regressions. (#68, reported by @likeitlotlot-commits) -
Noisy ensure during full level indexing on landscape-heavy projects. The level indexer loads each World purely to enumerate placed actors, which lazily initializes a
ULandscapeSubsystem; tearing the world down then tripped a GC ensure. The indexer now unregisters every landscape proxy's components before drivingUWorld::CleanupWorld, so the subsystem deinitializes cleanly with zero ensures and no residency cost. (#67, reported by @likeitlotlot-commits)
A big one. Two major surfaces land here: the MCP LLM Ergonomics Pack (universal response shaping, schema-tagged param kinds, fuzzy-match dispatch errors, MCP tool annotations, cursor pagination, proxy JSONL call log, Niagara temporal-control + stateless-emitter pack) and Reflection Intelligence (deterministic reflection layer for architectural-decision lookup, repo-risk signals, UE 5.7 UHT reflection edges, replication inspection, read-only pipeline composers, and index maintenance). Zero LLM calls inside the new surface, zero embeddings, zero network, zero new optional dependencies.
Public in-tree action count: 1387 actions across 25 in-tree namespaces (1384 at v0.17.0 ship + the [Unreleased] cppreflect_query("list_class_specifiers") follow-up + the [Unreleased] network-completeness reflect_query("rebuild_reflection_index")). Live monolith_discover() reports 1610 across 29 namespaces when extension plugins are loaded — those advisory totals do not affect the public release headline. With the experimental town-gen registration (bEnableProceduralTownGen=true) the in-tree total rises by +45 to 1431. Authoritative per-namespace breakdown lives in Docs/SPEC_CORE.md §12.
Six new in-tree namespaces: decision, risk, cppreflect, network, pipeline, plus the [Unreleased] reflect index-maintenance namespace.
-
decision_querynamespace (5 actions, Phase 1) from the newMonolithReflectionIntelmodule. Deterministic markdown decision-record harvest — specs, plans,CHANGELOG.md,.claude/rules/— intodecision_records+decision_supersedesSQLite tables on top ofEngineSource.db. Actions:list_decisions,get_decision,list_stale,find_supersession_chain,find_referent_decisions. Three heuristic tiers with distinct confidence floors: YAML frontmatterdecision: true/status:(0.90),## ADR-N/## Architectural Decisionheaders (0.85), markdown header followed within 8 lines by a paragraph containingbecause/rationale/evidence/decision:(0.65). Lazy bootstrap on first call +FCoreUObjectDelegates::ReloadCompleteDelegaterefresh on Live Coding / UBT hot-reload. Every action carries the v0.17.0 ergonomics surface:EMonolithParamKind::DiskPathonpath_filter,readOnlyHint + idempotentHint, universal response shaping (_fields/_omit/_compact_json), opaque base64+JSON cursor pagination on the two list-style actions. -
UMonolithReflectionIntelSettingsUDeveloperSettings (Editor Preferences → Plugins → "Monolith Reflection Intel"). Surfaces toggles + tuning across all four phases:bEnableDecisionMining,DecisionMinConfidence,DecisionMarkdownRoots,bIndexProjectPluginReflection([Unreleased], defaulttrue),bIndexMarketplacePluginReflection([Unreleased], defaultfalse),bIndexEnginePluginReflection,UHTArtefactRoot,bEnableGitCoChangeMining,MaxCoChangeWindowCommits,MaxCommitFileCount,GitMiningNoiseFilter,bEnableNetworkReplicationAudit,bEnablePipelineComposers. INI section:[/Script/MonolithReflectionIntel.MonolithReflectionIntelSettings]inConfig/MonolithSettings.ini. -
([Unreleased]) Plugin-aware scan scope for the reflection indexers — no new actions, no count change. The CppReflect + Network UHT-artefact indexers no longer scan the project game module alone. Scope is driven by
IPluginManager::GetEnabledPlugins()along a game-module → project-plugin → marketplace ladder.bIndexProjectPluginReflection(defaulttrue) scans every enabledLoadedFrom == Projectplugin's UHT artefacts;bIndexMarketplacePluginReflection(defaultfalse) also scans enabled engine-installed marketplace plugins (LoadedFrom == Engineunder/Plugins/Marketplace/); Epic engine built-ins stay excluded (governed bybIndexEnginePluginReflection, default off). This is the change that makes RPC + replicated-class detection work on real projects — those declarations live in project plugins, which are now in scope by default. Verified E2E via a project-only force-reindex: game module alone ~30 artefacts → with project plugins on 337 (project-plugin Server RPCs + replicated classes) → with marketplace flag also on 927 artefacts / 745 UClasses. No engine source-symbol reindex is triggered — the ladder only widens the UHT-artefact scan. -
risk_querynamespace (5 actions, Phase 2) for repo-level risk signals. Actions:get_hotspot_score(per-file blended churn × LOC score),get_cochange_pairs(files that frequently change together with a given anchor file),get_file_churn,get_release_window_hotspots,list_conditional_gates(#if WITH_*macros +bHas*3-location probes +MONOLITH_RELEASE_BUILDbypasses). Mines git viaFPlatformProcess::CreateProcagainst each nested repo's.git/, skipping any path without.git/present. Hotspot score formula is deterministic and traceable:0.6 * normalised_churn + 0.4 * normalised_loc. Co-change pair detection caps per-commit file count atMaxCommitFileCount(default 50) to suppress tree-wide refactor + initial-import noise. Writes into four new SQLite tables:git_file_churn,git_cochange_pairs,risk_hotspot_scores,reflect_conditional_gates. -
source_query("audit_module_dep_reality")action (Phase 2, cross-namespace registration). Catches the LNK2019 bug class where UPROPERTY (or any reflection-touching declaration) references a foreign-module type whose owning module is missing from the declaring module'sBuild.csPrivate/PublicDependencyModuleNames. UHT generatesZ_Construct_*_NoRegistercalls that link against the foreign module's API macro at link time; the failure surfaces as a confusing LNK2019. Algorithm: regex-parse every*.Build.csunderSource/for declared deps, regex-extract type-bearing reflection declarations from every*.h/*.cpp, resolve each extracted type againstEngineSource.db's symbol → owning module mapping, emit a violation when the owning module is not declared and not on the implicit-deps whitelist (Core,CoreUObject,Engine,Projects,RHI,RenderCore). Cursor-paginated withmodule_filtersubstring scope. The audit handler is owned byMonolithReflectionIntelbut registers onto the existingsourcenamespace for caller ergonomics — agents already discoversource_queryfirst. -
cppreflect_querynamespace (6 actions — 5 in Phase 3a + 1 [Unreleased]) for UE 5.7 reflection-edge queries. Actions:get_uclass(UHT-derived UCLASS record — parent class, specifiers, source path),list_uproperties(cursor-paginated UPROPERTY surface for a UCLASS),list_ufunctions(cursor-paginated UFUNCTION surface, with rawEFunctionFlagsbitfield + return type + per-param JSON),find_interface_impls(every C++ UCLASS implementing a given UINTERFACE),find_class_specifier(every UCLASS carrying a given specifier), andlist_class_specifiers([Unreleased] — returns the distinct universe of tokens stored in theflagscolumn ofreflect_uclasses, each with a per-token class count; those tokens are UHT metadata keys likeIsBlueprintBase/BlueprintType/Abstract, NOT raw C++ specifiers, so it's the discovery companion telling you whatfind_class_specifiercan match). [Unreleased] also madefind_class_specifierforgiving: alias map (Blueprintable→IsBlueprintBase), honest not-captured note for specifiers UHT drops (MinimalAPI/NotBlueprintable), case-insensitive matching. Drives a regex sweep over UHT artefacts (Intermediate/Build/Win64/.../Inc/<Module>/UHT/*.gen.cpp) cross-joined withIAssetRegistry::GetDependenciesfor the asset side. No tree-sitter dependency, no ThirdParty vendoring — substrate is deterministic file IO plus 8 regex patterns derived from real.gen.cppinspection. Writes into six new SQLite tables:reflect_uclasses,reflect_uproperties,reflect_ufunctions,reflect_uinterfaces,reflect_uinterface_impls,cpp_asset_edges(asset path → C++ class via/Script/<Module>package dependency, coarseedge_kind='package_dep'in Phase 3a). Cross-joining the UE class graph withIAssetRegistrylets agents answer "what assets reference this C++ class?" without manual reference-viewer walks. -
network_querynamespace (4 actions, Phase 4a) for UE 5.7 replication inspection. Actions:list_replicated_classes(UCLASSes carrying at least one replicated property, sortable by replicated-property count — as of the [Unreleased] network-completeness workstream this captures bareUPROPERTY(Replicated)+DOREPLIFETIMEviaCPF_Netin addition toReplicatedUsing, verified E2E against the project's replicated character/attribute classes),list_rpc_functions(filterreflect_ufunctionsby replication specifier fromEFunctionFlagsas of [Unreleased] — covers project plugins by default via the [Unreleased] scan-scope ladder, so it returns the project's actual RPCs, verified E2E with the project's project-plugin Server RPCs; the prior "empty because game-module-only" status is resolved),list_onrep_handlers(everyOnRep_*UFUNCTION paired with the property it covers viareflect_replicated_properties.rep_notify_funcjoin),audit_unbalanced_onreps(catches typo + rename drift —ReplicatedUsing=OnRep_Xdeclarations whoseOnRep_Xfunction does not exist). Drives a second UHT-artefact regex sweep (independent of Phase 3a's reader for separation of concerns) over per-propertyMetaDatablocks plus theCPF_Netproperty flag. Writes into one new SQLite table:reflect_replicated_properties. All four cursor-paginated. -
pipeline_querynamespace (2 composer actions, Phase 4a).pr_review— changed-files PR review composer; for each path inchanged_files[], fans outrisk_query("get_hotspot_score")+risk_query("get_cochange_pairs")+decision_query("list_decisions", path_filter=path)+source_query("audit_module_dep_reality")+ optionalblueprint_query("audit_cdo_drift"), aggregates per-path; hard cap 100 paths per call.release_readiness— release pre-flight composer; bundlesmonolith_status()+decision_query("list_stale")+risk_query("get_release_window_hotspots")+ the sentinel-list audit + CHANGELOG completeness audit specced in.claude/rules/scoped/monolith-release.md. Both composers are read-only end-to-end. Both fan out serially on the game thread; noParallelFor, no async dispatch. -
reflect_querynamespace (1 action, [Unreleased] network-completeness workstream).rebuild_reflection_index(no params) — a project-only force-rebuild of the RI reflection tables (reflect_uclasses/reflect_uproperties/reflect_ufunctions/reflect_uinterfaces/reflect_uinterface_impls/cpp_asset_edges+reflect_replicated_properties). Re-runs the RI indexers over PROJECT UHT artefacts only (Epic engine built-ins excluded). With the [Unreleased] scan-scope ladder, "project" means the game module plus enabledLoadedFrom == Projectplugins by default (and marketplace plugins when enabled), so a rebuild repopulates project-plugin reflection — which is whynetwork_query("list_rpc_functions")returns the project's RPCs after a rebuild. Exists because after an indexer code change there's no other clean repopulation trigger — lazy bootstrap only fires on table-absence,OnReloadCompleteonly on Live Coding, andsource_query("trigger_reindex")is the full-engine reindex. WRITE/maintenance action (not read-only), idempotent (wipe-and-rewrite per indexer in a single transaction), non-destructive. -
Four cross-namespace audit actions (Phase 4a). Each owned by
MonolithReflectionIntelbut registered onto the host namespace's adapter for caller ergonomics.material_query("audit_orphan_materials")—/Game/path scan viaIAssetRegistry::GetReferencersfor zero-reference materials.niagara_query("audit_cross_asset_refs")— broken/stale asset reference scan over Niagara systems/emitters joined against Phase 3a'scpp_asset_edges.blueprint_query("audit_cdo_drift")— Blueprint child CDOs that override a native C++ parent's default value (catches drift when a native default changes upstream and BP children silently keep the stale override).project_query("audit_orphan_assets")— project-wide zero-reference scan cross-validated against Phase 3a'scpp_asset_edges(surfaces assets referenced only from C++ but not from BP / asset graph). All four read-only + cursor-paginated;path_prefixcarriesEMonolithParamKind::AssetPathfor automatic\→/rewrite with surfaced warning. -
Automation tests for Reflection Intelligence. +4 under
Monolith.ReflectionIntel.Decision.*(SchemaBootstrap,HeuristicAccuracy,SupersessionChain,StalenessFlag). +6 underMonolith.ReflectionIntel.Risk.*(RiskSchemaBootstrap,ChurnAggregation,CoChangePairSymmetry,HotspotScoreFormula,ConditionalGateSweep,MonsterCommitSuppression). +tests underMonolith.ReflectionIntel.ModuleDepReality.*. +4 underMonolith.ReflectionIntel.CppReflect.*(CppReflectSchemaBootstrap,UClassFixtureExtraction,InterfaceImplResolution,AssetGraphJoin). Phase 4a (network + pipeline + cross-namespace audits) shipped with manual smoke only — automation tests deferred. All fixture corpora live underSource/MonolithReflectionIntel/Private/Tests/Fixtures/. Disposable test DBs atFPaths::AutomationTransientDir(); the realEngineSource.dbis never touched by tests.
-
Universal response-shaping params on every action (Phase 1.0). Three opt-in universal params reshape the JSON response post-dispatch:
_fields: string[](whitelist top-level response keys),_omit: string[](blacklist, mutually exclusive with_fields),_compact_json: bool(drop top-level keys whose value isnull/""/{}/[]). Underscore-prefixed to avoid collisions. Registry-level allowlist so no per-action schema migration was required. Top-level keys only in Phase 1; JSONPath / JMESPath grammar deferred. -
Schema-tagged param kinds via
EMonolithParamKind(Phase 1.0 + 1.1 sweep). New enum onFParamSchemawith four variants:Other(default, never rewritten),AssetPath(dispatcher rewrites\→/with a surfaced warning),DiskPath(native OS path; explicit opt-out for clarity),GameplayTag(reserved). 87-file sweep tagged ~913 builder call sites asAssetPathand ~18 asDiskPath. NewFParamSchemaBuildersugar overloadsRequiredAssetPath/OptionalAssetPath/RequiredDiskPath/OptionalDiskPath. Back-compat preserved — every existing.Required(...)/.Optional(...)call site defaults toKind == Otherand opts OUT of path normalisation. -
did_you_meanfuzzy match on dispatch errors (Phase 2). Unknown-action and unknown-namespace dispatch failures now carryerror.data.suggestions— top-3 closest registry keys with normalised scores via UEAlgo::LevenshteinDistance. Snapshot-then-unlock pattern keeps the hot dispatch lock free of scoring work.error.data.kindfield disambiguates"action"vs"namespace"suggestions. -
MCP-spec tool annotations on
tools/list(Phase 2). Five audited read-only / idempotent dispatchers (monolith_discover,monolith_status,monolith_guide,monolith_reindex,source_query) now serialisereadOnlyHint/destructiveHint/idempotentHint/titlehints so LLM clients can pre-filter destructive vs read-only calls without dispatching them first. Annotations only emitted when at least one field is non-default. -
source_query("search_source")cursor pagination (Phase 3). New opaque base64+JSONcursorin-param andnext_cursor/total_estimateout-params. Page 0 emitstotal_estimatevia a server-side SQLite FTS5MATCH COUNT(*). Rerun-slice scheme (FTS5bm25()rank is unstable under inserts/deletes). Hard cap 1000 rows total per query. Query-hash mismatch returns a cleanINVALID_CURSORerror rather than silently serving the wrong slice.project_query("search")cursor pagination deferred — architecturally blocked byFMonolithIndexDatabase::FullTextSearch's UNION-and-resort without deterministic ordering. -
Proxy-side JSONL call log (Phase 4). Both proxies now emit one line per call to
Saved/Logs/MonolithCalls.jsonl(project-root-relative). Eight-field schema:ts(ISO-8601 UTC),namespace,action,params_hash(SHA-1 hex over canonicalised params JSON),duration_ms,ok,error_code(omitted on success),result_bytes. Native proxy (Tools/MonolithProxy/monolith_proxy.cpp) and Python fallback (Scripts/monolith_proxy.py) implement the same schema. Opt-out: setMONOLITH_CALL_LOG=0. Local-only, no phone-home. User-managed rotation (delete the file to reset). Native proxy requiresbuild_proxy.batrebuild + Claude Code MCP reconnect to engage; Python picks up on next Claude Code start. -
Niagara temporal-control surface (+9
niagara::actions). Collapses scattered timing edits (per-propertyset_system_property+set_simulation_stage_property+set_module_input_valueagainstEmitterState/InitializeParticle) into composite, intent-named writers. System-level (4):get_system_timing(bundled read ofWarmupTime/WarmupTickCount/WarmupTickDelta/bFixedTickDelta/FixedTickDeltaTime/bRequireCurrentFrameData),set_warmup_profile,set_fixed_tick_delta,set_require_current_frame_data. Emitter (2):set_emitter_loop_profile(composite write of EmitterState loop topology),get_emitter_timing_summary(read aggregator pulling loop topology + sim_stages +InitializeParticlelifetime fields into one response). Sim-stage aliases (2):set_sim_stage_iteration_count,set_sim_stage_execute_behavior— both alias atopset_simulation_stage_propertywithstage_index/stage_nameselector convention. Particle lifetime (1):set_particle_lifetime(convenience write toInitializeParticle— Direct mode with constantLifetimeor Random mode with min/max). -
Niagara stateless-emitter factory —
create_stateless_emitteraction. Creates a standaloneUNiagaraStatelessEmitter(Lightweight Emitter) asset for programmatic test-asset setup. UsesFindObject<UClass>(nullptr, "/Script/Niagara.NiagaraStatelessEmitter")+ type-erasedNewObjectto avoid coupling to Niagara'sInternal/Stateless/headers. Pairs with new stateless-aware branches added toset_emitter_loop_profileandget_emitter_timing_summary(see Changed).
-
Niagara
set_emitter_loop_profileandget_emitter_timing_summarynow handleUNiagaraStatelessEmitterassets natively. The previous stateless-detection points (which early-outed with the placeholder "set_stateless_loop_profile coming" hint) now dispatch into real reflection-based read/write paths against the protectedEmitterState(FNiagaraEmitterStateData) UPROPERTY. Detection usesStaticLoadObject+ class-name match; the stateful module-routed path is unchanged. New optionalloop_duration_modeparam onset_emitter_loop_profileaccepts"Fixed"/"Infinite"(maps toENiagaraLoopDurationMode— meaningful only on stateless). Responses on the stateless branch include astateless: trueflag;get_emitter_timing_summaryadditionally returnsnullfor all 4InitializeParticlelifetime fields andsim_stages: []. Same action names, same call surface — purely an additive dispatch branch. -
Both proxies advertise the universal params on every tool's inputSchema. Native
Tools/MonolithProxy/monolith_proxy.cppand PythonScripts/monolith_proxy.pynow emit_fields/_omit/_compact_jsonon every tool descriptor returned fromtools/list. The native proxy requires abuild_proxy.batrebuild + Claude Code MCP reconnect to engage end-to-end; the Python fallback picks up the change on next restart. -
Symmetric params-string unwrap on the
monolith_branch ofHandleToolsCall— mirrors the pre-existing_querybranch behaviour so meta-namespace tools (monolith_discover,monolith_status,monolith_guide, etc.) accept the same nested-paramsshape that domain tools already handled.
-
Response-shaping post-filter (
_fields/_omit/_compact_json) now engages on the MCP wire. Two-investigator bug-investigator consensus identified the root cause: Claude Code's MCP client serialises array-valued top-level arguments as JSON-encoded strings rather than native arrays.MonolithJsonUtils::ReadStringArrayParam(and the_compact_jsonbool read insideApplyResponseShaping) now carry a string-fallback mirroring the existingparams-key special-case inMonolithHttpServer.cpp. Native-array path remains FIRST. Live verification:monolith_status({_fields:["version","total_actions"]})returns exactly{"version":"0.17.0","total_actions":1609};editor_query("get_recent_logs", _fields:["count"])returns{"count":1}instead of the prior full envelope.
-
Phase 3b — tree-sitter source-vendored native gameplay-tag tracking.
cppreflect_query("list_native_tags")plusreflect_native_tag_decls+reflect_native_tag_externstables. UHT does not emit native-tag metadata (UE_DEFINE_GAMEPLAY_TAG_*/UE_DECLARE_GAMEPLAY_TAG_EXTERN), so source-level parsing is the only honest substrate. Vendoringtree-sitter-cpp(~50MB source weight, ~1.1M-line generatedparser.c) was too much against the current ~12MB Monolith release-zip baseline. Phase 3b would also backfill the currently-emptyreflect_uproperties.blueprint_visibility/.specifiersfields plus a finer-grainedcpp_asset_edges.edge_kind. -
Phase 4b — two audit families blocked on Phase 3b substrate.
gas_query("find_tag_consumers" / "find_grant_paths" / "find_revoke_paths")needs native-tag declaration tracking.animation_query("audit_thread_safety")needsreflect_uproperties.specifierspopulated. Both deferred together — the combined value is real but not blocking the release-readiness work Phase 4a directly addresses. (BareUPROPERTY(Replicated)detection, previously a Phase 4b item, LANDED in the [Unreleased] network-completeness workstream —list_replicated_classesnow captures it viaCPF_Net.) -
Phase 5+ — cursor codec consolidation. The base64+JSON cursor envelope is now duplicated five times across Decision / Risk / CppReflect / SourceAudit / Network adapters. Refactor target for the next release window.
-
Automation tests added. Phase 1.0 brought +11 under
Monolith.ResponseShaping.*andMonolith.ParamKind.*. Phase 2 brought +10 underMonolith.FuzzyMatch.*andMonolith.CursorPagination.*. Reflection Intelligence brought +4 / +6 / +4 across Decision / Risk / CppReflect (Phase 4a deferred to manual smoke). All passing. -
No
*.Build.cschanges for the ergonomics surface; oneAssetRegistryadd toMonolithReflectionIntel.Build.csfor Phase 3a. No.upluginchanges. No new module dependencies for the ergonomics work. Phase 3a neededAssetRegistryforIAssetRegistry::GetDependenciesjoins.
A small, focused release between the v0.15.0 ergonomics framework and the next major surface. Headline work: a five-action preview & inspection surface expansion in the editor:: namespace (renders + structural-data reads for tech-art and AI agents), one MCP-introspection hint that points agents at the schema-discovery surface before they guess parameter names, and two component-persistence fixes from a community-reported regression.
Public in-tree action count is approximate (Editor expanded 29 → 33). Per the Action Count Discipline this EXCLUDES sibling-plugin actions — sibling plugins are not in the public release zip. With the experimental town-gen registration (bEnableProceduralTownGen=true) the in-tree total rises by +45.
-
Preview & inspection surface expansion (
editor::namespace): extendededitor::capture_scene_previewasset_typeenum to supportstatic_mesh,skeletal_mesh(with optionalanimation_path+seek_timefor posed capture), andwidget(UMG viaFWidgetRendererwithscaleDPI multiplier). Neweditor::capture_material_grid(N material instances side-by-side under shared lighting; auto-grid layout viaceil(sqrt(N))with optionalcolumnsoverride). Neweditor::capture_with_overlay(5 engine debug-view modes: wireframe, normals, uv_density, lightmap_density, shader_complexity). Neweditor::inspect_material_pbr(PBR texture parameter classification + ORM/ARM/MRA channel-packing detection — pure reflection, no rendering). Neweditor::inspect_texture_channels(per-channel R/G/B/A min/max/mean statistics + optional per-channel split PNGs). All editor-only. AI discoverability via newmonolith_guiderecipe entries. -
Schema-discovery hint in MCP
initializeinstructions (Issue #62, @middle233). Both the C++ HTTP server (HandleInitialize) and the Python proxy now point AI agents atmonolith_discover,describe_query("action_schema"), andmonolith_guidefrom the initial handshake — so clients read schemas instead of trial-and-erroring parameter names. No new action; widens the existing introspection surface's discoverability.
-
Component persistence (Issue #63, @Heiselisha):
mesh.convert_to_hism,mesh.place_spline, andai.place_smart_object_actornow callAActor::AddInstanceComponenton every component they create, so the components survive level save/reload. Convert-to-HISM also gains a pre-destroy guard that preserves source actors if HISM instance creation reports a count mismatch.mesh.place_splinefollow-up: root + spline components now spawn withEComponentMobility::Staticso saved spline data round-trips through the level's Static-mobility persistence path.
Big thanks to @middle233 for Issue #62 (MCP schema-discovery guidance gap) and to @Heiselisha for Issue #63 (HISM / spline / SmartObject component persistence regression). Both issues drove fixes that ship in this release.
This release rolls up everything since v0.14.10 (20 commits). Headline work: the MCP ergonomics framework (bulk_fill_query + describe_query routing to 12 per-namespace adapters), a dataset read/edit ergonomics pack (17 new blueprint actions for round-tripping DataTables / CurveTables / StringTables + seed_data_asset), the UI/Blueprint MCP gap-closure sweep (9 new actions across 4 phases + the 0516 UI gap-audit Tier 1–4), the new monolith_guide editorial action, and two community PRs (#58, #60). Two reflection/enum correctness fixes, plus a sibling-plugin-reference scrub in shipping comments.
Public in-tree action count is approximate. Per the Action Count Discipline this EXCLUDES sibling-plugin actions — sibling plugins are not in the public release zip, so their actions are not counted here. With the experimental town-gen registration (bEnableProceduralTownGen=true) the in-tree total rises by +45. Authoritative per-namespace breakdown lives in Docs/SPEC_CORE.md §12.
-
MCP ergonomics framework —
bulk_fill_query+describe_query+ 12 per-namespace adapters. Two new top-level Monolith MCP namespaces land inMonolithCore:bulk_fill_query(2 actions:apply,list_namespaces) anddescribe_query(2 actions:schema,list_targets). Framework primitives ship asBlueprintTypeUSTRUCTs inMonolithCore:FBulkFillSpec(input shape —target_namespace,target, nested JSONtree,dry_run,strict),FDryRunReport(per-fieldFieldWrites/SilentDrops/Clamps/Errors),FSchemaDescriptor(recursive descriptor tree — type names, ImportText sample forms,range_min/range_max,enum_values,conditional_ondiscriminators).FMonolithReflectionWalkeris the single source of truth for UE 5.7FProperty/FStructProperty/FArrayProperty/FMapProperty/FSetProperty/FObjectProperty/FSoftObjectProperty/FEnumPropertyrecursive descent —InspectTree(...)returns a dry-run report without mutation,ApplyTree(...)performs writes under a caller-owned transaction.FMonolithBulkFillRegistryis the string-keyed singleton dispatcher; zero compile-time linkage fromMonolithCoreinto adapter modules (per-namespace adapters self-register from their owning module'sStartupModule) preserves the Issue #30 / #32 hard-import hazard class.FMonolithDryRunGuardis the RAII helper that opts an adapter into the framework'sdry_run:truepreview-without-persist semantics. 12 per-namespace adapters ship in this release: blueprint (set_cdo_properties,describe_cdo_schemaaliases registered for symmetry with the existingset_cdo_property/get_cdo_propertiesreads), gas (AttributeInitDataTablefill_kind,#if WITH_GBAstub-pattern —Register()runs unconditionally, body switches on the gate), inventory (an optional sibling-plugin adapter, conditionally gated), ui (Input-action DataTable as single transaction, slot-property scoped describe), ai (EQSTests,BlackboardKeys,SmartObjectSlotsfill_kinds), niagara, material, audio (MetaSound paths#if WITH_METASOUND), mesh, animation, logicdriver (#if WITH_LOGICDRIVERstub-pattern), combograph (#if WITH_COMBOGRAPHstub-pattern). H5 stub-adapter pattern uniform across all conditional-gate adapters:RegisterAdapteralways runs; adapter body conditionally compiled; release-build#elsereturns a clean typed error rather than silently no-op'ing. Net surface: ~50 new C++ files, ~8276 LOC, zero new module dependencies. Per-namespacefill_kindcatalogues live in each per-module SPEC's new "Bulk Fill & Describe Surface (2026-05-11)" section. -
MonolithUI Tier 2 close-the-loop primitives — 8 new
ui_queryactions.rename_widget(rename a widget tree entry by path),add_widget_variable(author a new variable on a Widget Blueprint),audit_focus_chain(walks the navigation graph and reports orphans / dead-ends / cycles),apply_token_binding(Tokenforge → widget property binding — MVP-STUB; issue #2-10b tracks full BP-graph node-write completion),list_widget_property_enums(returns the legal enum value list for a UMG property — feeds the property-allowlist authoring loop),convert_textblock_to_common(in-placeUTextBlock→UCommonTextBlockupgrade preserving text/font/color),set_action_bar_button_class(re-targets aUCommonBoundActionBar's button class without rebuilding the bar),dump_blueprint_compile_log(returns the structured compile-log warnings/errors for a Widget Blueprint by path — closes the gap wherecompile_widgetreturned only success/failure boolean).MonolithUI.Build.csgainsBlueprintGraph+Projectsdependencies to support the graph-walk and project-file paths. -
MonolithUI Tier 3 headline scaffolders — 4 new
ui_queryactions.scaffold_main_menu(full main-menu Widget BP: title, vertical button stack, focus chain wired, reduce-motion gate, hardware-visibility border),scaffold_settings_panel_with_tabs(TabList + ActivatableSwitcher with one tab per Settings DataTable row, focus return on close),scaffold_pause_menu(push-to-stack ActivatableWidget with Resume/Settings/Quit, input mode swap, blur backdrop),build_menu_from_spec(data-driven menu builder from a JSON spec — MVP; issue #3-18b tracks multi-screen aggregation). All four return the saved asset path + a verification structure listing the widgets / animations / styles created. New fileSource/MonolithUI/Private/CommonUI/MonolithCommonUITemplateActions.cpp(993 lines). -
MonolithUI Tier 4 polish + docs.
convert_button_to_commongains Tokenforge auto-detect (when a project has the Tokenforge plugin installed,convert_button_to_commonwill auto-apply the matching design token to the newUCommonButtonBaseif a binding can be inferred from the source button's style).parent_classlookup-by-name doc improvements (clarifies which fallback resolution paths are tried).set_initial_focus_targetUPROPERTY contract documented (the action authors aUPROPERTYreference on the widget, not a transient binding — survives BP recompile).compile_widgeterrors[]surface documented (the array is always present, empty on success, populated with structured warning + error entries on failure). New "CommonUI Property Allowlist Coverage" section inSPEC_MonolithUI.md.-32011 ErrTokenforgeProviderAbsenceerror contract confirmed parity with-32010 ErrOptionalDepUnavailable— the two codes share semantics (optional sibling-plugin runtime absent) but distinct discriminators so AI clients can route token-related failures separately from EffectSurface failures. -
mesh.import_meshskeletal mesh + animation import support — PR #58 by @4698to. The action gains two optional parameters that widen the import surface without breaking existing static-mesh callers:import_as_skeletal: bool=false(when true, the FBX importer is configured to produce aUSkeletalMeshinstead of aUStaticMesh— auto-resolves rig + skeleton hierarchy from the FBX), andimport_animations: bool=false(when true and the source FBX contains animation tracks, additionally imports the bundledUAnimSequenceassets alongside the mesh). Schema-only widening — no new action registered, the existing singlemesh.import_meshhandler dispatches on the new params. Silent-promote behaviour: ifimport_animations=trueis requested but the FBX carries no anim tracks, the action succeeds and reportsanimations_imported: 0rather than erroring — callers needing strict animation presence must inspect the count post-call. Full per-param semantic table lives inspecs/SPEC_MonolithMesh.md§Import. Closes the prior workaround of authoring a transient FBX import factory viaeditor.run_pythonfor cross-skeleton retarget flows. -
niagara.{get_system_summary,get_emitter_summary}semantic-detail surface +niagara.validate_systemevent-chain reasoning — PR #60 by @middle233. Both summary actions gain an optionaldetail_level: "compact" | "full"parameter (default"compact"). Compact returns the existing terse payload plus per-emitterrole_hint,spawn_location_mode,requires_persistent_ids,consumed_events[]/generated_events[]summary fields; full additionally emits per-emitterincoming_events[],outgoing_links[],event_generators[],location_modules[],semantic_notes[], plus system-levelinter_emitter_link_count+independent_burst_emitters[]+inter_emitter_topology[].validate_systemnow reasons about inter-emitter event chains: walks the system topology once viaCollectTopologyEdges, classifies each emitter's role from a name-substring + module-graph topology heuristic (event_source/event_receiver/burst_receiver/independent_burst/shell_event_source/trail_follower/trail_or_ribbon/independent_emitter), surfaces unresolvedSourceEmitterIDwarnings, warns when a receiver consumes an event its named source does not generate (GenerateDeathEvent/GenerateLocationEvent/GenerateCollisionEventmodule-name probes), and emitsrequires_persistent_idsguidance for any emitter participating in an event chain. Schema-only changes for all three actions — no count delta (niagara stays 109). Maintainer hardening on top of the PR: (1) O(N)AnalyzeEmitterSemanticcache inHandleValidateSystem— the PR calledAnalyzeEmitterSemanticonce per emitter in the outer validation loop AND once per source-emitter in the inner event-chain lookup, producing O(N^2) graph walks on event-heavy many-emitter systems. Replaced with a single pre-pass that populates aTMap<FGuid, FMonolithNiagaraEmitterSemantic>keyed by emitter handle GUID (same key used by the serialisedincoming_events[].source_emitter_idfield, so the lookup matches the payload contract exactly); inner loop is nowSemanticCache.Find(SourceGuid). (2) Dead-branch drop in the newGetGraphForHandleUsageanon-ns helper — the PR included aSystemSpawnScript / SystemUpdateScriptswitch case that fell through toGetSystemSpawnScript()(never returning the Update graph), but the only callerCollectEmitterModulesiterates emitter-stage usages only — removed the dead branch to keep the helper honest. Design-notes block landed inSPEC_CORE.md§14. -
monolith_guideMCP action — section-keyed editorial cross-namespace guide for AI agents. Newguideaction in themonolithmeta-namespace (monolithnamespace 4 → 5:discover,status,update,reindex,guide), backed by a newFMonolithGuideToolstatic class inMonolithCore. Serves a hybrid payload: hand-authoredDocs/MONOLITH_GUIDE.md(loaded viaFFileHelper, cached behind a session-livedFCriticalSection-guardedTOptional<FString>, split on^##H2 headers) plus a live registry overlay — per-namespace action counts from the runningFMonolithToolRegistryand the plugin version, so counts always match the live build. Six sections:onboarding,recipes,decisions,errors,skills_map,gotchas. Callmonolith_guide()for the full index + all sections, ormonolith_guide(section="recipes")to return a single section and bound context cost; an unknown section returns a validation error listing the valid keys. Audience is external public-Monolith users with no projectCLAUDE.md, private skills, or agent registry. Deliberately omits a pipelines section (cross-linked toSPEC_CORE.md§13, not re-authored) and a per-namespace action table (that isSPEC_CORE.md§12 +Docs/references/MCP.md);skills_mappoints atSkills/<topic>/SKILL.mdrather than inlining bodies. Pull-only, zero per-success-call cost — no success response carries guide content; the only breadcrumb is a singleguide_hintstring on the no-filtermonolith_discover()response. Offline parity viamonolith_query.exe monolith guide. The markdown cache refreshes on editor restart (no live file-watcher). -
Dataset read/edit ergonomics — 17 new
blueprintactions for round-trip authoring of DataTables, CurveTables, and StringTables. LLM-friendly read → edit → write loop for the three table asset types, all engine-generic (reflection + string class/struct resolution), zero sibling-plugin coupling, zero new module deps. Reuses the MonolithCore reflection framework (DescribeStructfor inline schema, theFDryRunReportshape for write previews). DataTable (8):read_data_table(rows plus theRowStructschema inline),describe_data_table_schema(schema only),set_data_table_rows(bulk upsert/add/update withdry_run+strict, per-field{path, current, proposed, ok, reason}reporting, oneBroadcastPostChangeper call),remove_data_table_row/rename_data_table_row/duplicate_data_table_row(row CRUD viaFDataTableEditorUtils),export_data_table(JSON or CSV viaGetTableAsJSON/GetTableAsCSV),import_data_table(JSON or CSV viaCreateTableFromJSONString/CreateTableFromCSVString, REPLACE semantics with aRowStructguard). CurveTable (5):read_curve_table(rich or simple key dump — time/value/interp/tangents),set_curve_table_keys(replace or merge keys, respects the empty-table rich/simple mode lock),add_curve_table_row/remove_curve_table_row/rename_curve_table_row. StringTable (3):read_string_table(namespace + key/source enumeration),set_string_table_entries(upsert/replace + namespace),remove_string_table_entry. DataAsset (1):seed_data_asset(create +bulk_fillpopulate in one atomic call). DataAssets otherwise round-trip through the existingbulk_fill_query(apply) +describe_query(schema) — no extra read/write action needed, documented in the per-module SPEC. New files:MonolithBlueprintDataTableActions.{h,cpp},MonolithBlueprintCurveTableActions.{h,cpp},MonolithBlueprintStringTableActions.{h,cpp};seed_data_assetinMonolithBlueprintStructActions. -
UI/Blueprint MCP gap-closure — 9 new actions across four phases. Engine-generic; foreign classes resolve by string/reflection, zero sibling-plugin coupling.
ui(5):set_widget_navigation_bulk(apply N navigation-rule writes then compile once, vs the per-call compile ofset_widget_navigation; per-entry failures non-fatal),dump_widget_navigation(read-only dump of per-directionUWidget::Navigationrules including Wrap/Stop/Escape that the Explicit-edge-onlyaudit_focus_chaincan't see),convert_border_to_common(in-placeUBorder→UCommonBorderpreserving variable identity, parent slot, and content child),reparent_widget_root(replace a Widget Blueprint root with a newUPanelWidget-derived class resolved by string, migrating children),set_widget_is_variable(first-class flip ofUWidget::bIsVariableto mark/unmark a tree widget as an exposed Blueprint variable). The four CommonUI-surface actions are#if WITH_COMMONUI-gated.blueprint(3):add_property_access(author aUK2Node_VariableGet/Setreading/writing a UPROPERTY on an arbitrary foreign class resolved by string viaFMemberReference::SetExternalMember+AllocateDefaultPins, so the value pin resolves to the property's real type instead of a wildcard — closes the cross-class variable get/set gap),override_parent_function(author a Blueprint override of an overridable parent function — including ones that RETURN a value, e.g.UCommonActivatableWidget::BP_GetDesiredFocusTarget→UWidget*, whichadd_functionand the event-node form can't do),save_dirty_assets(save all currently-dirty Blueprint + Widget Blueprint packages in one sweep with apath_prefixfilter — closes the data-loss window after a batch of dirtying edits).describe(1):action_schema(return a registered action's full param schema — names, types, required, defaults, aliases, descriptions — bytarget_namespace+action, so callers stop trial-and-erroring param names). Plus ergonomics that don't change the count:get_variables include_bind_widgetsnow enumerates BOTH C++BindWidget/BindWidgetOptionalrefs AND pure-BlueprintbIsVariabletree widgets (deduped), widget-contextCallFunctionresolution, NodeGuid-on-create across every node-creation path,add_function/add_nodeparam aliases (function_name,function_class,member_class,pos), and a clearget_widget_treeerror whenasset_pathis empty/missing.
-
MonolithUI Tier 1 correctness fixes — 6 fixes across the always-on + CommonUI surface. (1)
MonolithUIStyleServicehash-cache mis-keying — the dedup cache was keying on object identity instead of content hash, so two structurally-identical style payloads got cached under different keys and Style Service stats over-reportedunique_styleswhile under-reporting cache-hit ratio. (2) CommonUI button allowlist additions —UCommonButtonBasemissing properties (MinPaddingDesired,bAutoCollapse,HoveredAudio) now writable throughset_widget_property. (3) Reduce-motion gate diagnostic improvement — when the project's reduce-motion setting is unset,wrap_with_reduce_motion_gatenow surfaces a structuredreasoninstead of failing with a generic "setting not found" error. (4)create_bound_action_bargains an optionalaction_button_classparameter — callers can now author a bound action bar with a custom button class in one call instead of authoring with the default class and patching afterward. (5)compile_widgetnow surfaceserrors[]andwarnings[]arrays in the response — the older boolean-only return shape masked recoverable compile warnings that callers needed to see. (6)set_widget_propertyacceptsvalueas an alias forproperty_value— closes the foot-gun where callers swapped between read (get_widget_propertyreturns undervalue) and write (which requiredproperty_value) and silently got nothing written. -
UserDefinedEnum fields inside a UserDefinedStruct now surface
enum_valuesin schema and accept display-name writes — were previously reported as a bareint32. A UserDefinedEnum field inside a UserDefinedStruct compiles to a plain numericFPropertywith noEnumassociation (UUserDefinedEnumisECppForm::Namespaced; the KismetCompiler only emitsFEnumPropertyforEnumClass), so the reflection walker reported it asint32with no enumerators and writes required the raw integer index. The walker now recovers theUEnumfrom editor-only UDS metadata (FStructureEditorUtils::GetVarDescByGuid→SubCategoryObject):DescribeStructemits the recovered enumerators (friendly display names) and the enum's name astype_name, improving the schema forread_data_table,describe_data_table_schema, everybulk_fill/describeadapter, anddescribe_query("schema"). A shared resolver (ResolveUserDefinedEnumToken) maps an incoming display or authored name to the enum's integer value beforeImportText, with bare-int back-compat, wired into theset_data_table_rowsandadd_data_table_rowwrite paths. Robust_MAXsentinel handling (IsAutoMaxSentinel) so enums without a sentinel never drop a real value. NativeFEnumProperty/FByteProperty-with-enum paths untouched (no regression). Editor-only (#if WITH_EDITOR), no new module deps. -
blueprint.create_user_defined_enumdropped the last enumerator of every enum it created — now authors all N. A freshly createdUUserDefinedEnumstarts with ZERO user enumerators (index 0 is already the auto_MAXsentinel;NumEnums() == 1). The old authoring loop rani = 1..N-1, callingAddNewEnumeratorForUserDefinedEnumonly N-1 times, then the display-name loop wrote the Nth name onto the_MAXslot —SetEnumeratorDisplayNamebounds-checks onlyidx < NumEnums(), so it silently produced an orphaned DisplayName. Net effect: every enum created via this action lost its LAST value — present only as an orphan display name, invisible at runtime (NumEnums,ImportText, the reflection walker). Fixed to author N enumerators (i = 0..N-1) so real entries occupy0..N-1and the_MAXsentinel lands at N; display-name and read-back loops now address all N real entries. Verified live: a 3-value enum reportsinternal_namefor all three and resolves a display-name write of the last value. -
NodeGuid correctness — every MCP node-creation path now assigns a valid
NodeGuid(gap #15).add_node,add_event_node,add_timeline,promote_pin_to_variable,add_comment_node, andadd_property_accessnow callUEdGraphNode::CreateNewGuid()so authored nodes carry valid GUIDs and no longer risk invalid-GUID warnings on compile/save. -
C2011 struct redefinition under unity builds in MonolithBABridge (PR #61 by @tc-imba).
DECLARE_LOG_CATEGORY_EXTERNforLogMonolithBABridgewas duplicated at file scope across two.cppfiles; the declaration is hoisted intoMonolithBAFormatterImpl.h(outside theWITH_BLUEPRINT_ASSISTguard) so both the BA-enabled and empty-shell log paths share a single declaration.
-
animation.add_anim_graph_nodenow supports arbitrary concrete custom AnimGraph node classes via an optionalnode_classparameter, while preserving the existing built-innode_typealiases. The action resolves loadedUAnimGraphNode_Basesubclasses by full path or unique short/class name, rejects abstract/non-AnimGraph/ambiguous/schema-incompatible classes before mutation, and keeps stock node aliases available for release builds. -
niagara.get_emitter_summaryevent_handlers[]array removed — breaking shape change (PR #60 by @middle233). The legacyevent_handlers[]payload (one entry perFNiagaraEventScriptPropertiescarrying{event_name, source_emitter_id}) is superseded by two richer surfaces emitted by the new semantic-detail pipeline:consumed_events[](canonicalised event-name list —DeathEvent/LocationEvent/CollisionEvent— emitted at bothcompactandfulldetail levels) andincoming_events[](full per-edge topology array withsource_emitter_name,source_emitter_id,execution_mode,spawn_number,max_events_per_frame, etc. —fulldetail level only). Callers readingevent_handlers[].source_emitter_idmigrate toincoming_events[].source_emitter_id(fullonly) orconsumed_events[]for the canonicalised list. All other existingget_emitter_summaryfields preserved (additive elsewhere). -
15 central error messages in MonolithCore (HTTP server + tool registry) now carry inline recovery guidance. The recovery hints fold directly into the existing
error.message/ErrorMessagetext at each of the 15 central error sites (HTTP request parse/dispatch + registry namespace/action lookup) — e.g. an unknown-namespace error now suggests checking theWITH_*compile-time gate, a malformed-request error names the expected shape. No schema change, no envelope change: no new field onFMonolithActionResult/FMonolithActionInfo, noRegisterAction(...)signature change, no per-success-call cost. MCP clients parsing the error text simply see longer, more actionable messages. Per-handler error text across the in-tree modules is unchanged — only the 15 central sites were salvaged.
-
Phase 5 SPEC backfill: 8 per-namespace SPECs gained a "Bulk Fill & Describe Surface (2026-05-11)" section documenting their adapter's
fill_kindcatalogue, sample tree, adapter-specific quirks, and v1.1 follow-ups:SPEC_MonolithAI.md,SPEC_MonolithNiagara.md,SPEC_MonolithMaterial.md,SPEC_MonolithAudio.md,SPEC_MonolithMesh.md,SPEC_MonolithAnimation.md,SPEC_MonolithLogicDriver.md,SPEC_MonolithComboGraph.md. The pre-existingSPEC_MonolithGAS.md,SPEC_MonolithBlueprint.md, andSPEC_MonolithUI.mdsections renamed to match the canonical heading. -
Neutralized private sibling-plugin references in shipping comments. Three comments in
MonolithUIsource named private sibling plugins by path/name (sibling-adapter paths plus an internal dev context) — these files are new in this release window and would publish for the first time. Replaced the specific private references with generic per-namespace-adapter phrasing; the technical rationale is preserved. No code change. -
Action count: ~1344 in-tree actions across 19 namespaces, closing the v0.15.0 window. A mid-window live snapshot via
monolith_discover()on 2026-05-11 read 1540 total across 23 namespaces (in-tree 1317 across 19; sibling-plugin total 223 =claudedesign11 +inventory158 +steam28 +substance26). The late-window additions land another +27 in-tree to reach ~1344:blueprint+20 (the 17 dataset read/edit actions plusadd_property_access/override_parent_function/save_dirty_assets),ui+5 (the Phase 3/4 gap actions plusset_widget_is_variable),describe+1 (action_schema), andmonolithmeta +1 (guide). Per the Action Count Discipline, the advertised public count EXCLUDES the sibling-plugin namespaces above — they are NOT in the public release zip. Counts re-verified against the release-candidate build; authoritative per-namespace breakdown inDocs/SPEC_CORE.md§12. (A pre-existingui/GAS-alias double-count in the headline19-namespacefigure is out of scope here; a holistic count audit is deferred.)
Big thanks to @4698to for PR #58 (mesh.import_mesh skeletal-mesh + animation import params), to @middle233 for PR #60 (event-aware Niagara summary semantics + validate_system event-chain reasoning), and to @tc-imba for PR #61 (MonolithBABridge unity-build C2011 fix + root-cause analysis). Author attribution preserved on every cherry-picked commit.
-
MetaSound document introspection action pack — 12 new
audio_queryactions (PR #18 by @alakangas, refactored into the existingMonolithAudiomodule). Read-only walk ofIMetaSoundDocumentInterface::GetConstDocument()→FMetasoundFrontendDocument. Distinct from the existing 25 MetaSound Builder API actions: those read live builder state during graph mutation; these read on-disk document state for arbitrary assets without an active builder session. Action list (all conditional onWITH_METASOUND):list_metasounds(project-wide enum),list_metasound_documents(per-asset page list),get_metasound_document(full doc walk),get_metasound_summary(lightweight counts),inspect_metasound_node_instance(per-node pin/edge details),get_metasound_document_connections(edge enumeration),get_metasound_document_variables(graph variables),get_metasound_user_parameters(public inputs/outputs),search_metasound_document_nodes(substring search),get_metasound_info(asset metadata),get_metasound_dependencies(external class deps + subgraphs),validate_metasound(lint pass). PR's original architecture proposed a separateMonolithMetaSoundmodule +metasound_querynamespace — landed refactored into existingaudio_queryper maintainer architectural preference (no new module, no new namespace). Action names disambiguate from the existing Builder-side actions (get_metasound_documentvs Builder-sideget_metasound_graph;inspect_metasound_node_instancevs Builder-sideget_metasound_node_info;get_metasound_document_connectionsvs Builder-sidelist_metasound_connections;get_metasound_user_parametersvs Builder-sideget_metasound_input_names). All 12 actions PIE-smoke-tested at port time. By @alakangas. -
FMetaSoundIndexerdeep indexer in MonolithIndex (PR #18 by @alakangas). NewSource/MonolithIndex/Public/Indexers/MetaSoundIndexer.h+.cpp. WalksUMetaSoundSource+UMetaSoundPatchassets at reindex time, opens viaIMetaSoundDocumentInterface::GetConstDocument(), iterates root-graph pages viaFMetasoundFrontendGraphClass::IterateGraphPages(const overload), and writes nodes / edges / variables / dependencies intoProjectIndex.dbfor cross-asset query viaproject_query. Sentinel-class registration mirrorsFNiagaraIndexer. Throttled viaFMonolithMemoryHelper::ShouldThrottle/ForceGarbageCollection/YieldToEditor(per-batch, GC every N batches). New settingbIndexMetaSounds(default true) under Editor Preferences → Plugins → Monolith → Indexing → Deep Indexers.MonolithIndex.Build.csgains a 3-location Metasound probe (enginePlugins/Runtime/Metasound, marketplace, top-level fallback) honouringMONOLITH_RELEASE_BUILD=1for binary-release safety (Issue #30 defense). Conditional onWITH_METASOUND. By @alakangas. -
animation.list_bone_tracksaction — PR #54 by @MaxenceEpitech. Returns{ count, bone_names: [..] }for aUAnimSequenceby walkingIAnimationDataModel::GetBoneTrackNames(TArray<FName>&). Closes the discovery gap beforeget_bone_track_keys— Skeleton bone listings include unanimated bones, so they're not a substitute. Wired intobatch_executealongside the other animation read actions. -
editor.run_console_commandaction — PR #54 by @MaxenceEpitech. Dispatches a console command via the firstAPlayerControllerof the active PIE world (so exec UFUNCTIONs on the possessed pawn fire correctly), falling back toGEngine->Execon the editor world when no PC is available. Returns which world type was used (pie/editor) and whether the PC path was taken. Maintainer hardening on top of the PR:GEnginenull-guard added to the fallback branch (returns clean error instead of dereferencing a null engine pointer); description string clarified that multi-client PIE routes to the first PlayerController found (no disambiguation). -
editor.start_pie+editor.stop_pieactions — PR #54 by @MaxenceEpitech.start_piequeues a Play-In-Editor session and refuses to queue a duplicate when a PIE world is already alive.stop_piecallsRequestEndPlayMapwhen a PIE world exists, no-op (withstopped: false) otherwise. Pairs with the existingrun_python/load_level(v0.14.9 Issue #50) actions for fully automated in-game test flows: load level → start PIE → run console cmds → stop. Maintainer hardening on top of the PR:start_pierewritten to pin to in-viewport mode viaFLevelEditorModule::GetFirstActiveViewport()+FRequestPlaySessionParams::DestinationSlateViewport+EPlaySessionWorldType::PlayInEditor(canonical pattern fromLevelEditorSubsystem::EditorRequestBeginPlayatLevelEditorSubsystem.cpp:264-277). Without this pin, the action would inherit the user's last-used PIE flavour (Simulate/NewWindow/ etc.) viaULevelEditorPlaySettings::LastExecutedPlayModeType— surprise factor for MCP callers expecting "start PIE" to mean "spawn player in active level viewport". Response now includesmode: 'in_viewport'for caller verification. -
animation.get_skeleton_preview_attached_assetsaction — PR #55 by @MaxenceEpitech. ReadsUSkeleton::PreviewAttachedAssetContainer(the editor-only[Preview Only]list shown in Persona's bone tree). Returns{ asset_path, attached_objects: [{ attach_point, attached_object, attached_object_class }, ...], count, transforms_stored: false }. Thetransforms_stored: falseflag documents that the container does NOT carry per-asset relative transforms (Persona attaches at the socket origin with the asset's natural pivot). Closes the gap where[Preview Only]attachments were only readable by parsing the.uassetbinary. Includes the UE 5.7 surface fix (commit42e771e) forFPreviewAssetAttachContainer::Num()/operator[](int32)— the olderGetNumAttachedObjects/GetAttachedObjectByIndex/GetAttachNameByIndexaccessors no longer exist in UE 5.7. -
animation.get_bone_ref_poseaction — PR #55 by @MaxenceEpitech. Returns reference (bind) pose transforms for a skeleton's bones in BOTH parent-relative AND component-space. WalksFReferenceSkeletononce to compute component-space via parent-index accumulation. Accepts abone_names: arrayfilter (default: all bones). Works on either aUSkeletonorUSkeletalMeshasset path —source_typefield in the response indicates which. Replaces the prior workaround of spawning a temporarySkeletalMeshActorto callGetSocketTransform()at bind pose. -
animation.{get,add,remove}_compatible_skeletonactions — PR #56 by @MaxenceEpitech. Three new actions wrappingUSkeleton::CompatibleSkeletons— the canonical UE5 mechanism that lets anims authored on one skeleton play on another (typical case: UE4 mannequin animation packs on UE5SK_Mannequin). Idempotent semantics:add_compatible_skeletonreturns disjointadded/already_compatiblebooleans and the resultingcount;remove_compatible_skeletonreturns disjointremoved/was_compatiblebooleans. Self-compat rejected with a clean error ("Cannot mark a skeleton compatible with itself").save: bool=truecontrols whetherUEditorAssetLibrary::SaveAssetruns after the mutation. Closes the prioreditor_query.run_pythonworkaround for cross-skeleton retarget setup.
-
MCP proxy startup tool-list stability for clients that do not refresh after
tools/list_changed. The native proxy and Python fallback now return a cached tool list when the editor is down, or a seed list of the stable namespace/meta tools on first run. This preserves Claude Code's normal auto-reconnect behavior and also keeps Codex-style deferred tool catalogs from starting with an empty Monolith surface when the AI session launches before Unreal Editor. -
animation.get_bone_track_keysrewritten to use non-deprecatedIAnimationDataModelAPI — PR #54 by @MaxenceEpitech. Old code read rawFRawAnimSequenceTrackvia the deprecatedIAnimationDataModel::GetBoneAnimationTracks()accessor (wrapped inPRAGMA_DISABLE_DEPRECATION_WARNINGS). That path returns the uncompressed source tracks which are missing on AnimSequences that have already been baked / compressed — so callers gotBone track not found: <bone>even when the bone was clearly animated and visible in the asset. Switched to the public, non-deprecated pair:IsValidBoneTrackName()to validate the bone (no false-positive on missing source tracks) andGetBoneTrackTransforms(FName, TArray<FTransform>&)to evaluate per-keyFTransforms (works regardless of underlying compressed storage). Adds an empty-track guard soAllTransforms.Num() == 0returns a clean error instead of producingnum_keys=0and a misleadingstart_frame > end_framemessage.
-
animation.get_bone_track_keysscalesarray semantics — now always populated regardless of source compression. Old code emitted thescalesJSON field only when the underlyingFRawAnimSequenceTrack::ScaleKeyshad entries (silently dropped scales when key counts diverged across pos/rot/scale arrays). New code emits scales for every keyframe in the requested range becauseFTransform::GetScale3D()is always defined. Behaviour shift for downstream callers: any tooling that usedlen(scales) == 0as a sentinel for "no scale animation" will mis-classify identity-scale tracks. Inspect the actualFVectorvalues to detect identity ({1, 1, 1}) instead. PR #54 by @MaxenceEpitech. -
blueprint.get_cdo_propertiesgains 3 optional filters — PR #57 by @MaxenceEpitech:owner_class_filter(case-insensitive substring on owner class name — skips inheritedAActor/APawn/ACharacterprops in one parameter),name_pattern(case-insensitive substring on property name),exclude_categories(case-insensitive exact match onCategorymetadata, e.g.["Replication", "Cooking", "HLOD"]). All additive; defaultnullkeeps the previous full-list output. Composes with the pre-existingcategory_filterandinclude_parent_defaultsoptions. Cuts JSON payload by ~90% in typical AActor-subclass inspection flows where most properties are inherited generic actor scaffolding rather than the asset's own surface.
-
PR #17 disposition: substantively superseded. PR #17 by @alakangas introduced
FMonolithMemoryHelper(memory-budget probe + GC-throttle primitives) plus retrofits to 6 indexers (Animation, Level, MeshCatalog, Niagara, DataTable, GAS). Master independently reached the same shape for the helper + 4 of the 6 retrofits (Animation/Level/MeshCatalog/Niagara) before the PR landed; remaining gaps are theFAssetCompilingManager::Get().FinishAllCompilation()guard hunks forDataTableIndexer.cpp(line ~24) andGASIndexer.cpp(line ~78), which will be cherry-picked from PR #17 with @alakangas authorship preserved at release time. The PR's settings additions (MemoryBudgetMB,DeepIndexBatchSize,PostPassBatchSize,GCFrequencyBatches,YieldTimeSeconds,bDeferFirstTimeIndex,bLogMemoryStats) are already on master with matching field shapes. -
Action count delta:
audio86 → 98, total 1274 → 1286, distinct 1270 → 1282 (with-town-gen 1319 → 1331). Verified live at v0.14.9 + Phase 3 build viamonolith_status+monolith_discover("audio"). TheWITH_METASOUNDgate keeps the new actions inert (and the indexer unregistered) when MetaSound is absent. -
Naming convention reinforcement. The non-uniform spelling in the UE 5.7 Metasound API (
FMetaSound...capital S for builder/asset/interface,FMetasound...lowercase s for document/graph/node/edge/vertex/variable/literal/class structs,EMetasound...lowercase s for enums) is preserved exactly in the ported code per Iron Law 1 source-verification. Documented in the v0.14.10 implementation plan atPlugins/Monolith/Docs/plans/2026-05-03-metasound-indexer-integration.md§ 8. -
Action count delta for PR #54: animation +1, editor +3, registrations 1290 → 1294 / in-tree active default 1286 → 1290 / distinct 1282 → 1286 / with town gen 1335 → 1339. Verified at v0.14.10 candidate build via
monolith_status+monolith_discover("animation")+monolith_discover("editor"). PR #54's 4 new actions are unconditional (noWITH_*gate) and not aliased — they bump all three count metrics by exactly +4. -
Action count delta for PRs #55 + #56: animation +5 (
get_skeleton_preview_attached_assets,get_bone_ref_pose,get_compatible_skeletons,add_compatible_skeleton,remove_compatible_skeleton). Cumulative v0.14.10 deltas vs v0.14.9: registrations 1290 → 1299 (+9), in-tree active default 1286 → 1295 (+9), distinct 1282 → 1291 (+9), with town gen 1335 → 1344 (+9). MonolithAnimation row 120 → 125 (+5 from #55/#56 layered on top of +1 from #54 baseline). PR #57 does NOT change the action count (purely additive optional params on the existingget_cdo_propertieshandler), but the schema reported bymonolith_discover("blueprint")now exposes 3 additional optional fields. All counts will be re-verified live at release-candidate build time viamonolith_status+monolith_discover("animation")+monolith_discover("blueprint"). -
PR #54 source-verified against UE 5.7 API surface.
IAnimationDataModel::IsValidBoneTrackName(IAnimationDataModel.h:243),IAnimationDataModel::GetBoneTrackTransforms(IAnimationDataModel.h:192, 2-arg overload),IAnimationDataModel::GetBoneTrackNames(IAnimationDataModel.h:257),FRequestPlaySessionParamsconstructor defaults (PlayInEditorDataTypes.h:130:SessionDestination=InProcess,WorldType=PlayInEditor),ULevelEditorSubsystem::EditorRequestBeginPlaycanonical PIE pattern (LevelEditorSubsystem.cpp:264-277). Maintainer hardening usesFLevelEditorModule::GetFirstActiveViewport+GUnrealEd->RequestPlaySessioninstead ofGEditor->RequestPlaySessionto keep the in-viewport pin authoritative. -
PRs #55 / #56 / #57 source-verified against UE 5.7 API surface. PR #55:
FPreviewAssetAttachContainer::Num()+operator[](int32)(PreviewAssetAttachComponent.cpp:62/71, returnsconst FPreviewAttachedObjectPair&),FPreviewAttachedObjectPair::GetAttachedObject()+AttachedTofield,FReferenceSkeleton::GetRefBonePose/GetParentIndex/GetNum/GetBoneName/FindBoneIndex(canonical hierarchy walk, mirrorsClothingSimulation.cpp:111+IKRetargetDetails.cpp:71). The deprecation note atSkeletalMesh.h:1811applies only to theUSkeletalMesh-sidePreviewAttachedAssetContainermirror — PR #55 reads fromUSkeleton, the canonical (non-deprecated) home. PR #56:USkeleton::AddCompatibleSkeleton(const USkeleton*)(Skeleton.h:741,ENGINE_API-exported, implSkeleton.cpp:276),USkeleton::RemoveCompatibleSkeletonraw-ptr overload (Skeleton.cpp:286),USkeleton::GetCompatibleSkeletons()returning iterableTSoftObjectPtr<USkeleton>container. PR #57:TFieldIterator<FProperty>(canonicalEFieldIterationFlagswalker atCoreUObject/Public/UObject/UnrealType.h:7023, mirror ofNiagaraNodeConvert.cpp:801),FProperty::GetMetaData(TEXT("Category"))(canonical patternPropertyHandleImpl.cpp:3111),FString::Contains(..., ESearchCase::IgnoreCase)(engine-stable since UE 4.x). No deprecated symbols touched.
Huge thanks to @alakangas for both PRs (#17 memory helper + indexer retrofits, #18 MetaSound indexer + introspection actions). Quadruple thanks to @MaxenceEpitech for shipping PR #54, PR #55, PR #56, and PR #57 — the bone-track discovery action + deprecated-API rewrite of get_bone_track_keys + PIE/console action triplet (PR #54), the two skeleton-introspection actions (PR #55, including the UE 5.7 FPreviewAssetAttachContainer API surface fix), the three CompatibleSkeletons actions (PR #56), and the three get_cdo_properties filter parameters (PR #57). Author attribution preserved on every cherry-picked commit.
-
editor.run_python+editor.load_levelactions — Issue #50, ported from @JCSopko's fork.run_pythonwrapsIPythonScriptPlugin::Get()->ExecPythonCommandEx(FPythonCommandEx&), supporting all three execution modes (execute_file,execute_statement,evaluate_statement) and theEPythonFileExecutionScopePrivate/Public split. Returns success status, captured Python log output (typed: info/warning/error), and the evaluated result forevaluate_statementmode.load_levelwrapsULevelEditorSubsystem::LoadLevel(AssetPath)— single-arg map swap with native semantics (closes current persistent level without saving). Together these replace common fallback-to-other-MCP patterns; agents now stay inside Monolith for Python escape-hatch + map swapping in integration tests / automation flows.Monolith.upluginenablesPythonScriptPlugin(engine-shipped Experimental plugin requires explicit enable). By @JCSopko. -
animation.copy_bone_pose_between_sequencesaction — PR #51 by @MaxenceEpitech. Reads the evaluated pose (track + ref-pose fallback) from a sourceUAnimSequenceat a given time and writes it as keys to a destination sequence for a list of bones. Closes the workflow gap whereget_bone_track_keysreturned "not found" for bones imported with sparse keys (no explicit track). Per-bone skip with structuredreasonrather than hard-fail. Maintainer follow-ups on top of the PR: (1) replaced the UE 5.6-deprecatedGetBoneTransform(FTransform&, FSkeletonPoseBoneIndex, double, bool)overload with the non-deprecatedFAnimExtractContext(SourceTime)form (dropsPRAGMA_DISABLE_DEPRECATION_WARNINGSshim that was masking a real warning); (2) addedbone_namesarray element-type guard — non-string entries now return-32602with index in the message, instead of silently skipping viaVal->AsString()returning empty; (3) addedSourceTimeclamp to[0, GetPlayLength()]withoriginal_source_time+clamped_source_timesurfaced in the response when the input was adjusted (out-of-range values previously sampled undefined positions).
-
blueprint.set_pin_defaultnow writesPin->DefaultObjectfor class-typed (PC_Class) and object-typed (PC_Object) pins — previously wrote the value string intoPin->DefaultValueonly, never touchingPin->DefaultObject. UE's reflection readsDefaultObjectfor ref-typed pins, so authored class/object values silently reverted to the pin's static base type at compile/load. Fix introducesMonolithBlueprintInternal::ResolveDefaultObjectForPin(header-only inline helper) accepting native class names withA/Uprefix retry (PC_Class only), object/class paths viaStaticLoadObject, and Blueprint class paths with auto_C-suffix retry. Type-constraint enforced againstPin->PinType.PinSubCategoryObject. Cross-category mismatch (class pin given an instance, object pin given a UClass) returns an error.set_pin_defaults_bulkandbatch_executeinherit the fix automatically (already delegate toHandleSetPinDefault). Soft refs (PC_SoftObject/PC_SoftClass) andPC_Interfacefall through to the existing primitives path; deferred until concrete demand surfaces. PR #52, Issue #53, by @danielandric.
-
AbilityTagsreflection lookup future-proofed against the engine's gradual rename toAssetTags(Issue #31) —MonolithGAS::FindAbilityAssetTagsPropertyheader-only helper tries the modernAssetTagsname first, falls back to the legacyAbilityTags. Both names work at UE 5.7, but a future engine version may complete the removal — the helper logs a one-time warning if neither is found, so the next break is loud rather than silent. Replaces the two directFindPropertyByName(TEXT("AbilityTags"))call sites inMonolithGASInspectActions.cppandMonolithGASScaffoldActions.cpp. No behavioural change at UE 5.7. -
macOS build CI workflow scaffold (Issue #25) —
.github/workflows/macos-build.ymltriggers onv*tag pushes and dispatches a macOS build job to a self-hosted runner labelled[self-hosted, macOS, monolith]. Mirrorsmake_release.ps1's release-build env (MONOLITH_RELEASE_BUILD=1,-DisableUnity, sibling-strip,Installed: truepatch, SHA256 emit,softprops/action-gh-releaseattach). Two known gaps documented in workflow-header comments: (1) self-hosted runner provisioning (Mac with UE 5.7 + Xcode CLT + ~150GB disk +UE_57env var), (2) project-shell gap —MonolithEditor.Target.csdoes not exist in the plugin source tree, so the workflow fails-fast with two resolution paths (commit a CI-only project shell into the plugin repo, OR point a project-path env var at a parent project on the runner). Workflow does not fire until the runner is online.
This release rolls up six work-streams: (1) a new in-tree module MonolithLevelSequence (8 actions, dedicated SQLite indexer, UE 5.7 custom-binding awareness) authored as PR #45 by community contributor @yashabogdanoff; (2) a major MonolithUI architecture expansion (Phase A–L) lifting the module from a flat action toolbox to a schema-driven Spec / Type Registry / Style Service / EffectSurface architecture, plus the box-slot primitive completion and a sequence of CommonUI button-conversion fixes; (3) delegate-node authoring for blueprint.add_node (ComponentBoundEvent, AddDelegate, RemoveDelegate, ClearDelegate, CallDelegate) shipped as PR #44 by @danielandric; (4) the editor.run_automation_tests + list_automation_tests action pair shipped as PR #48 by @MaxenceEpitech, letting agents drive the UE automation framework in-process without a second editor instance or commandlet; (5) a stack of CDO / index hardening fixes — TInstancedStruct CDO serialization (PR #40 by @fp12), the RF_Transient-on-UPackage corruption-of-cross-package-refs root-cause fix (PR #43, Issue #42, by @danielandric), the add_event_node-on-UUserWidget widget-Tick fix (PR #46, Issue #47, by @danielandric), and the CreateBlueprint flow RF_Transient-leak fix (PR #49 by @JCSopko); (6) the new mesh.export_mesh FBX exporter (PR #41 by @MaxenceEpitech), inverse of the existing import_mesh. Plus an action-count audit, public-doc path-leak scrub, and a sibling-plugin-name scrub across docs, specs, and the v0.14.7 release notes.
Public action count: 1271 across 16 in-tree namespaces in the Monolith plugin proper (1267 distinct handlers; the +4 delta is the GAS UI binding aliases registered cross-namespace into ui::). Action namespaces from internal sibling plugins are not part of this release — sibling counts are specced in their own repos. With the experimental town-gen registration (bEnableProceduralTownGen=true), the in-tree total rises to 1316 (+45). For the authoritative per-namespace breakdown see Plugins/Monolith/Docs/SPEC_CORE.md §12.
-
MonolithLevelSequence — new in-tree module (8 actions,
level_sequencenamespace) — PR #45 by @yashabogdanoff. Indexes everyULevelSequenceasset end-to-end, not just those carrying a Director Blueprint. The indexer captures five custom SQLite tables:level_sequence_directors(one row per LS with a Director, with name + counts);level_sequence_director_functions(own userFunctionGraphsplusK2Node_CustomEventinUbergraphPagesplus the syntheticSequenceEvent__ENTRYPOINT*UFunctions UE generates for Sequencer Quick-Bind entries, classified asuser/custom_event/sequencer_endpoint; inherited base methods and compilerExecuteUbergraph*dispatchers excluded — matches theMonolithBlueprintget_functionsconvention);level_sequence_director_variables(eachNewVariablesentry, declaration order);level_sequence_event_bindings(everyFMovieSceneEventtrigger / repeater across event tracks, with binding context + Director-function FK resolved via a per-asset post-pass JOIN); and the newlevel_sequence_bindingstable (everyFGuid+BindingIndexpair regardless of event-track presence — covers the UE 5.7UMovieSceneCustomBindingfamily onSequence->GetBindingReferences()that legacyFindPossessable/FindSpawnablewould miss). Eight actions ship:list_directors,get_director_info,list_director_functions,list_director_variables,list_event_bindings,find_director_function_callers,list_bindings, pluslevel_sequence.pingsmoke. Indexer write paths useFSQLitePreparedStatementend-to-end (CONTRIBUTING.md SQL discipline), no FK onls_asset_id(core'sResetDatabase()would block reindex DELETEs as Issue #42's class),LogMonolithLevelSequencelog category (mirrorsMonolithAI/MonolithGAS). TwoUMonolithSettingstoggles (bIndexLevelSequences/bEnableLevelSequence, both defaulttrue) follow the existingbIndex*/bEnable*split. Spec atDocs/specs/SPEC_MonolithLevelSequence.md; skill atSkills/unreal-level-sequences/. Ships with full UE 5.7 custom-binding classification (possessable/spawnable/replaceable/custom) so modern Spawnables stop misresolving as legacy upgrade-stub possessables. -
MonolithUI Phase A–L architecture expansion —
ef9cc0alands the schema-driven Spec / Type Registry / Style Service / EffectSurface architecture that promotesMonolithUIfrom a flat action toolbox: 23,585 LOC added across UISpec / UISpecBuilder / UISpecSerializer / UISpecValidator, the Hoisted Design Import verbs (AnimationCore, AnimationEvent, FontIngest, Gradient, RoundedCorner, Shadow, TextureIngest), the Spec Builders sub-tree (PanelBuilder / LeafBuilder / CommonUIBuilder / EffectSurfaceBuilder), the Type Registry and Property Allowlist, the Style Service, the Animation MovieScene builder, and the UI Registry Subsystem. Phase L lands the EffectSurface optional-provider decoupling (reflectiveUClassprobe; zero compile-time dependency on the provider;-32010 ErrOptionalDepUnavailablereturned for the 10 EffectSurface action handlers when the provider is absent — seeDocs/specs/SPEC_MonolithUI.md§ "Error Contract"). Module action count moves to 117 module-owned (66 always-on + 51 CommonUI conditional onWITH_COMMONUI) plus the 4 GAS UI binding aliases registered cross-namespace intoui::for a tooling total of 121. -
blueprint::add_nodedelegate-node family (PR #44 by @danielandric) — Closes the workflow gap where authoring a UMG button event or a runtime delegate binding required manual Designer clicks. Five newnode_typevalues:ComponentBoundEvent(the green event-entry node spawned by clicking "+" beside a component delegate in Designer; validates the component variable resolves on the BPGeneratedClass, that the delegate isBlueprintAssignable, and rejects duplicate(component, delegate)pairs BP-wide viaFKismetEditorUtilities::FindBoundEventForComponent— matches the editor's own dedupe across ubergraph pages; works on widget BPs becauseFindComponentPropertyaccepts UMG widget properties);AddDelegate(Bind Event to ...runtime-binding node,SetFromPropertywalksDelegateProp->GetOwnerClass()so inherited delegates resolve to the declaring class); plusRemoveDelegate,ClearDelegate, andCallDelegatecovering the rest of the multicast-delegate node family that derive fromUK2Node_BaseMCDelegate(closes the asymmetry where the editor's right-click menu exposes Bind / Unbind / Unbind all / Call but Monolith only authored Bind).resolve_nodegains dry-run support for all five;SerializeNodeextended with aK2Node_BaseMCDelegatebranch covering future delegate node types transparently.add_nodes_bulkandbatch_executepick up all five with no dispatch-layer changes. -
editor.run_automation_tests+editor.list_automation_testsactions (PR #48 by @MaxenceEpitech) — Run / enumerate UE automation tests by full-path prefix (e.g.MazeLegends.Bow) viaFAutomationTestFramework::StartTestByName+StopTestfrom inside the running editor. No PIE, no commandlet, no second editor process — sidesteps the.uprojectfile-lock that preventsUnrealEditor -ExecCmds="Automation RunTests <prefix>"from running while the editor is open.run_automation_testsreturns a structured JSON summary (success,total,passed,failed,skipped) plus per-test results with error messages, so agents can drive a regression suite end-to-end (e.g. "lock down a calibrated weapon's data-asset values; assert across edits"). Latent / async tests (TickTests-driven) are not exercised by this sync path and are reported asskippedfor visibility. Editor action count: 22 → 24. -
mesh::export_meshFBX export action (PR #41 by @MaxenceEpitech) — Inverse of the existingimport_mesh. CallsUExporter::FindExporter+RunAssetExportTaskwith the engine's built-in FBX exporter, supporting bothUStaticMeshandUSkeletalMesh. Round-trip workflow for editing project meshes in DCC tools (Blender, Maya) directly from the agent — no manual Asset Actions → Export needed. Params:asset_path(string, required),file_path(absolute output FBX path, required),replace_existing(bool, defaulttrue). Returns{ asset_path, file_path, asset_class, file_size_bytes }. -
blueprintCDO read serializesTInstancedStructproperties (PR #40 by @fp12) —PropertyToJsonValuenow detectsFInstancedStructproperties, unwraps the concrete inner struct, and emits a JSON object with a__structfield (theUScriptStructasset path) plus all inner fields serialized recursively. Previously,TInstancedStructfields fell through to the generic struct branch and returned empty/incorrect data, breakingget_cdo_property(and any other CDO read path) for DataAssets that useTInstancedStructfor polymorphic data — e.g.UCyTargetingPatternentries in CyberVikings. The original PR added aStructUtilsmodule dependency; that was subsequently dropped inecdb42fbecauseFInstancedStructand friends relocated intoCoreUObject's public surface in UE 5.5+ (existing#include "StructUtils/InstancedStruct.h"paths resolve transparently fromCoreUObjectnow). -
MonolithUI box slot primitives — sizeRule / fillWeight + min/max desired —
bee2c03liftsUVerticalBoxSlot/UHorizontalBoxSlotfrom{hAlign, vAlign, padding}to{hAlign, vAlign, padding, sizeRule, fillWeight}in the Spec round-trip, and addsSizeBoxMinDesired*/MaxDesiredHeight*overrides to the read path alongside the existingWidth/HeightOverridecapture. Closes the §6.3.3 surface-map gap so thedump_ui_spec→build_ui_from_specround-trip preserves the box-slot fields agents actually tune. -
JSON-RPC error catalogue documented in
SPEC_CORE.md(ef9cc0a) — Standard codes (-32700parse,-32600invalid request,-32601method not found,-32602invalid params,-32603internal error) mirror JSON-RPC 2.0; Monolith's server-defined-32000..-32099range carriesErrOptionalDepUnavailable=-32010for the optional-sibling-plugin-absent case (first consumer: the 10 EffectSurface action handlers). Reserved range-32011..-32019left open for future "optional dep" codes. Constants inPlugins/Monolith/Source/MonolithCore/Public/MonolithJsonUtils.h.
-
MonolithIndexRF_Transientcorruption of cross-packageTObjectPtrsaves (PR #43, Issue #42, by @danielandric) —TryUnloadPackagewas settingRF_Transienton indexed-assetUPackages to encourage GC, butRF_Transientis a save flag (ObjectMacros.h:565, "Don't save object."), not a GC flag.GARBAGE_COLLECTION_KEEPFLAGSin editor isRF_Standaloneonly (GarbageCollection.h:28);RF_Transientis never consulted by reclamation. When GC failed to reclaim a package (any package still pinned by a BP CDO, editor watcher, asset registry, or thumbnail cache), the liveUPackageretainedRF_Transient.UObject::IsAsset()(Obj.cpp:2733) then returnedfalsefor every asset in that package, and cross-packageTObjectPtrsaves silently stripped refs to those targets — no warning, no error. The corruption survived cold restart because the indexer pass re-applied the flag on every editor startup. Triggered under default settings on any asset class with a registered deep indexer routing throughTryUnloadPackage(UInputAction,UMaterial,UStaticMesh,UNiagaraSystem,UWorld). Fix: dropSetFlags(RF_Transient). The GC-eligibility intent is fully delivered byPackage->ClearFlags(RF_Standalone), which is preserved. -
blueprint.add_event_noderesolves inherited overrides on non-AActorparents (PR #46, Issue #47, by @danielandric) —HandleAddEventNodealiasesAActor-style event names to theirReceiveXcounterparts before walking the parent class chain (e.g.Tick→ReceiveTick). Non-AActorBlueprintImplementableEventhosts use the bare names —UUserWidgetdeclaresTick, notReceiveTick. The alias-resolved walk therefore returned no match and the action silently fell through to theK2Node_CustomEventbranch, producing a custom event titledTickthat compiled but never fired on widget tick. Authoring widget-Tickchains viaadd_event_nodewas blocked. Fix: when the alias-resolved walk finds noUFunctionAND the alias actually changed the input name, retry the parent-chain walk with the original un-aliasedEventName. On a hit, realign bothEventFNameandResolvedEventNameso the downstream override-uniqueness check,SetExternalMembercall, and response telemetry all reference the function that exists on the resolvedDeclaringClass. UE 5.7 confirmsUUserWidget's function name isTick— the local C++ symbolReceiveTickEventin the compiler is a misleading variable name over aGET_FUNCTION_NAME_CHECKED(UUserWidget, Tick)lookup (Engine/Source/Editor/UMGEditor/Private/WidgetBlueprintCompiler.cpp:1044). -
blueprint.create_blueprintflow no longer leaksRF_Transientonto fresh BPGCs (PR #49 by @JCSopko) — Two operations inHandleCreateBlueprintdiverged from the canonicalIAssetTools::CreateAssetpath (AssetTools.cpp:1718-1782) and together formed theRF_Transientleak path observed in HOFF 6 (Cozy SquirrelTamagotchi, 2026-04-30 session): four BPs created with stale.uassetpaths on disk, multi-stepset_cdo_propertybetween create and save, overlapping prior-sessiondelete_assetscalls — allsave_assetcalls returnedsaved:false, then a load viaLinkerLoad.cpp:5032crashed on a serial-size-mismatch reading the partial-bytes CDO. Removals: (1)Package->FullyLoad()afterCreatePackage—CreatePackagenever touches disk (UObjectGlobals.cpp:1040-1050), soFullyLoadon the existing-in-memory hit path forces a serialization read that pulled staleRF_Transientflags from a leftover.uassetinto the live package;AssetTools.cpp:1755-1772omits this call. (2) RedundantFKismetEditorUtilities::CompileBlueprintafterFKismetEditorUtilities::CreateBlueprint—CreateBlueprintalready callsFBlueprintCompilationManager::CompileSynchronouslybefore returning (Kismet2.cpp:514-516); the second compile triggered a reinstance pass that propagatedRF_Transientonto the BPGC. Inline comments cite the engine-source rule each removal depends on so future readers can verify rather than re-derive. -
run_automation_testsregister-filter widening + class-name lookup + crash guard (1eaf84cfollow-up to PR #48 by @MaxenceEpitech) — Two bugs found while smoke-testing the new action against a real game-module test suite. (1)FAutomationTestFramework::RequestedTestFilterdefaults toSmokeFilteronly; game-module tests typically register withProductFilter, soGetValidTestNames()returned 395 engine tests and 0 project tests on a fresh editor session. Fix:SetRequestedTestFilterto a union of all filter buckets (Smoke|Engine|Product|Perf|Stress|Negative) before enumerating. (2)StartTestByNamelooks up the registry by class name (e.g.FBowDataAssetTest), not the human-readable full path (MazeLegends.Bow.DataAsset). Passing the full path failed silently, leftGIsAutomationTesting=false, and the subsequentStopTesttrippedcheck(GIsAutomationTesting)→ editor crash. Fix: useInfo.GetTestName()(= class name) as the lookup key, pass the full path as the optionalInFullTestPathargument so engine logs still show the readable name. Also gate onContainsTest()up-front so a stale or malformed entry producesstatus=skippedinstead of crashing. Verified: 3/3 pass on a real test suite, regression case (intentional value drift inDA_Bow.ArrowScale3P) returnsfailed=1with the assertion message captured inresults[].errors. -
MonolithUI box-shadow hardening for single-child wrappers (
194c6d9) — Box-shadow application was synthesizing a wrapper widget around each shadowed widget; when the wrapper held a single child the shadow placement could leak through the parent slot. The hoistedShadowActionsnow hardens this case with explicit single-child-wrapper handling, plus a 244-LOCApplyBoxShadowTestsbattery that locks the contract. -
MonolithUI cleans up failed shadow widget insertions (
6e50be1) — When shadow application failed mid-insertion the partially-inserted shadow widget would survive, polluting the WidgetTree. The action now walks back the partial mutation on failure so the WBP is left untouched. -
MonolithUI CommonUI button child-variable retirement is safe (
914bdcc) — Converting an existing button to a CommonUI button retired the original button's child variables; the previous path could leak the retired variable into the post-conversionWidgetTree. The retirement path is now driven byMonolithUICommonhelpers that take the child variable down cleanly across the BP recompile. -
MonolithUI CommonUI button conversion GUID cleanup (
0dd4fe1) — On CommonUI button conversion the source button's GUID identity was not being retired alongside the widget retirement; subsequentdump_ui_specruns could surface a phantom GUID with no live widget. The conversion now scrubs the source GUID in the same pass. -
MonolithUI Spec Builder dry-run is a true no-op (
64f79c9) —dry_run=trueonbuild_ui_from_specpreviously cancelled theFScopedTransactionat end but had already created the package, run widget construction, and compiled the blueprint by that point — so a dry-run could leave a transientUWidgetBlueprintbehind on disk if something failed betweenCreatePackageand the cancel. The dry-run path now runs validation +AssetRegistryoverwrite/parent inspection + diff counting before any package creation, widget construction, transaction, compile, or save; ondry_run=trueit returns directly from the inspection phase. Plus a 271-LOC roundtrip-fidelity test pass and 224-LOCLeafBuildertest pass.
-
MonolithUI Phase L EffectSurface decoupling (
ef9cc0a) — The 10 EffectSurface action handlers used to compile-time-depend on an external widget runtime provider that supplied the EffectSurface widget classes; that compile-time link prevented the public Monolith release zip from carrying those handlers cleanly. They are now invoked through a reflectiveUClassprobe on registered widget classes, withMonolithUIcarrying zero compile-time dependency on the provider. When the provider is absent the 10 handlers return-32010 ErrOptionalDepUnavailable— the action remains in the registry (so callers can still introspect viamonolith_discover) and the rest ofui::is fully functional. Themake_release.ps1$LeakSentinelslist is the build-time defence against accidental optional-provider symbol leakage into public release DLLs. -
Monolith.upluginDescription and per-namespace counts refreshed for v0.14.8 (82f4e84) — Description updated to 1271 in-tree actions across 16 in-tree domains; per-namespace counts updated (Mesh 240 → 194 default-active, Editor 22 → 24, UI 96 → 121); LevelSequence 8 added; experimental town-gen registration condition (bEnableProceduralTownGen=true) called out. Sibling-plugin actions deliberately excluded from the in-tree count. Wiki submodule pointer bumped to3584630("docs: refresh wiki for v0.14.8") which carries the matching action-count corrections across 5 wiki pages. -
Public docs scrubbed of absolute user paths (
7719ad9) — Absolute Windows project-root paths replaced with neutral<project-root>/<YourProject>placeholders inCHANGELOG.md(auto-updater example),Skills/unreal-build/unreal-build.md(UBT command example), andTools/MonolithProxy/README.md(.mcp.jsonproxy paths). Path-leak hygiene per the author-attribution audit rules — literal local paths were leaking maintainer drive-layout into shipping documentation. -
Action count audit baseline restated as 1271 in-tree across 16 namespaces (
e6866c4) — Re-verified against the livemonolith_discover()registry on 2026-04-30. Editor 22 → 24 (+2 from PR #48). UI 96 → 121 (Phase A–L expansion: 66 always-on + 51 CommonUI + 4 GAS aliases). Mesh 240 → 239 (one experimental town-gen action retired). With town gen registered: 1316 (+45). Sibling-plugin live-registry total reaches higher when host-project siblings are loaded; that delta is intentionally outside the public count.
-
Sibling-plugin name scrub across public docs, specs, wiki, and v0.14.7 release notes (
e1042bc,dd2e232,e2d6891,b47edc6,1d06c95) — Sibling plugins are private internal work and shouldn't be enumerated by name in public release notes, public specs, or the public wiki. Five-commit sweep acrossCHANGELOG.md,Docs/API_REFERENCE.md,Docs/SIBLING_PLUGIN_GUIDE.md,Docs/SPEC_CORE.md,Docs/specs/SPEC_MonolithUI.md,Scripts/make_release.ps1,Source/MonolithCore/Public/MonolithSettings.h,Source/MonolithIndex/Public/MonolithIndexSubsystem.h,Source/MonolithUI/Public/Spec/UISpec.h,Source/MonolithUI/Public/Spec/UISpecSerializer.h, theMonolithIndexProjectFindByType action, and the wiki submodule pointer. Two locations in the v0.14.7 entry rewritten: header now reads "Action namespaces from internal sibling plugins are not part of this release" instead of enumerating the four siblings; the Changed section drops the per-sibling action-count breakdown but retains the public-action-count discipline rationale. Tagv0.14.7stays ata8982a7(matches the shipped zip's git state); older release entries left as-published. -
StructUtilsmodule dependency dropped fromMonolithBlueprint(ecdb42f) —FInstancedStructand friends relocated toCoreUObject's public surface in UE 5.5+ (Engine/Source/Runtime/CoreUObject/Public/StructUtils/). TheStructUtilsmodule token added toMonolithBlueprint.Build.csby PR #40 is no longer needed — resolves transparently via theCoreUObjectpublic dep. Eliminates a UBT warning and pre-empts the eventual hard-removal of the deprecated plugin (already markedDeprecatedEngineVersion=5.5). -
MonolithLevelSequenceindexer write paths use prepared statements (8b7cf15) —CONTRIBUTING.mdrequires "All SQL must use prepared statements to prevent injection. Never use string formatting to build SQL queries." The indexer'sINSERT/UPDATE/DELETEpaths were initially usingFString::Printfwith manual single-quote escaping (action handlers were already using prepared statements). This commit switches all indexer write paths toFSQLitePreparedStatementand removes theEscapeSql/SqlTexthelpers. Two new helpers added in the anonymous namespace:BindNullableString(binds NULL for emptyFStrings via the no-argSetBindingValueByIndex(int32)overload) andExecWithInt64(convenience forDELETE/UPDATE WHERE col=?single-int64-binding shape). Naming hygiene:path_filterparameter renamed toasset_path_filterinlist_directorsso both glob filters across the namespace share the same name (consistent withfind_director_function_callers).LogMonolithLevelSequenceDECLARE/DEFINEpair added; module startup + indexer-registration log lines routed through it instead ofLogMonolith. -
Redundant Level Sequence INI overrides retired (
bb36f5c) — BothbIndexLevelSequencesandbEnableLevelSequencedefault totrueinUMonolithSettingsUPROPERTY initializers (MonolithSettings.h), so restating them inConfig/MonolithSettings.iniwas a no-op and stood out from convention — no other module carves out its own labelled section in the defaults INI. C++ defaults remain authoritative.
-
MonolithGAS + MonolithIndex still hard-link
GameplayAbilities— the v0.14.7-flagged plan to migrate this toOptional: true+WITH_GAMEPLAYABILITIESsource gate did not land in v0.14.8.MonolithGAS.Build.cs:14still carriesGameplayAbilitiesunconditionally inPublicDependencyModuleNames;MonolithIndex.Build.cs:32carries it unconditionally inPrivateDependencyModuleNames; neither module has abHasGameplayAbilities3-location probe; no#if WITH_GAMEPLAYABILITIESguards exist at any GAS API call site in either module;Monolith.upluginretainsGameplayAbilitiesas a hard dependency (no"Optional": trueflag);make_release.ps1$LeakSentinelsstill excludes the module per the v0.14.7 rationale. Functionally safe today under the .uplugin hard-dep auto-enable contract — the engine guaranteesGameplayAbilitiesis loaded before any Monolith DLL initialises, so the hard-link cannot fault on a fresh end-user install. TheMonolithAIF22 retrofit pattern (bHasStateTree/bHasSmartObjects3-location probe +MONOLITH_RELEASE_BUILD=1force-OFF + per-.cpp#if WITH_<MACRO>guards) remains the implementation reference. Migration deferred to a future release; the gap is documented rather than hidden.
-
@yashabogdanoff — PR #45 the entire
MonolithLevelSequencemodule: indexer + 5 schema tables (incl. UE 5.7 custom-binding awareness viaSequence->GetBindingReferences()), 8 actions, prepared-statement refactor, dedicated spec + skill + README integration. Substantial multi-commit greenfield contribution that extends Monolith's deep-indexer architecture into a new asset family. -
@danielandric — PR #43
RF_Transient-on-UPackage root-cause fix (Issue #42) — the canonical "obvious-looking save flag, devastating GC consequences" trap. PR #44 the full delegate-node family foradd_node(ComponentBoundEvent+AddDelegate/RemoveDelegate/ClearDelegate/CallDelegate), closing the asymmetry where Monolith only authored the editor's Bind verb. PR #46 theadd_event_node-on-UUserWidgetwidget-Tickfix (Issue #47) — the misleadingReceiveTickEventC++ variable name was bait, the real engine name isTick. -
@MaxenceEpitech — PR #48 the
editor.run_automation_tests+list_automation_testsaction pair (and the follow-up1eaf84cfilter-widen + class-name-key + crash-guard hardening), plus PR #41 themesh.export_meshFBX exporter. The automation actions are particularly load-bearing: they let agents drive UE's automation framework in-process without spawning a second editor or commandlet, sidestepping the.uprojectfile-lock entirely. -
@JCSopko — PR #49
CreateBlueprintflowRF_Transientleak fix. Engine-source-cited removal of two operations (FullyLoadafterCreatePackage; redundantCompileBlueprintafterCreateBlueprint) that diverged fromIAssetTools::CreateAsset's canonical path. Closes the HOFF 6 four-BP corruption-on-save repro from the 2026-04-30 Cozy SquirrelTamagotchi session. -
@fp12 — PR #40
TInstancedStructCDO read-path serialization. Polymorphic-data DataAssets (e.g.UCyTargetingPattern) now round-trip throughget_cdo_propertycleanly with__structtyping.
Full diff: v0.14.7...v0.14.8
This release rolls up four work-streams: (1) responsible-disclosure security response to #38 (CORS lockdown, MCP kill-switch, auto-update SHA256 verification, default-off auto-update); (2) F22 P0 SmartObjects + StateTree gating retrofit — closes the same class of bug as #30 and #32 where end users hit C1083/LNK2019 on plugins they hadn't enabled in their .uproject; (3) the Phase J fix sprint (audio/BT/GAS validation + observability + spec corrections); (4) StructUtils deprecation cleanup post-F22 — the deprecated plugin's headers relocated into CoreUObject in 5.5+. Plus PR #37 (community contribution by @MaxenceEpitech: anim graph property setter + native-component overrides + extended HTTP retry), the CommonUI M0.5 action pack (50 new actions), and PR #39 by @danielandric (recursive cradle sub-case + walker unification).
Public action count: 1239 across 16 namespaces in the Monolith plugin proper. Action namespaces from internal sibling plugins are not part of this release. For authoritative per-namespace breakdown see Plugins/Monolith/Docs/SPEC_CORE.md §12.
Security (#38)
Public responsible-disclosure response to a security audit by @playtabegg. The CORS finding was the only realistically exploitable item (browser tab pinging localhost while editor is open); the rest were defence-in-depth hardening.
-
CORS restricted to localhost origins — the previous wildcard CORS header allowed any browser tab on any origin to hit the localhost MCP listener while the editor was open. Now strictly checks
Originagainstlocalhost/127.0.0.1/[::1]patterns. -
MCP HTTP server kill-switch (
bMcpServerEnabled) — settable viaProject Settings → Plugins → Monolithor environment variable. When false, the in-process HTTP listener never binds; the rest of the plugin still works (offlinemonolith_query.exeetc.). Defaulttrueto preserve existing behaviour. -
Auto-update opt-in default
false(bAutoUpdateEnabled) — closes a small window where the C++ default (true) was used before the shipped INI default (false) loaded, allowing auto-update to fire without explicit opt-in on a fresh project. - SHA256 verification of auto-update tarballs — auto-update path now hashes the downloaded tarball against the release manifest before extraction. Previously the tarball was trusted on download.
-
SECURITY.mddisclosure policy — published. Future findings via private email rather than public issue comments. - README MCP-exposure section — explicit documentation of what the MCP HTTP server exposes, what it does NOT expose, and how to disable.
-
audio::create_test_waveaction (F18) — procedurally generates a sine-toneUSoundWavefor test fixtures with no asset dependencies. Validatesfrequency_hz(20–20000),duration_seconds(0.05–5.0),sample_rate({22050,44100,48000}),amplitude((0,1]). UE 5.7FEditorAudioBulkData::UpdatePayload(FSharedBuffer, Owner)payload write (legacyLock/Realloc/Unlockremoved in UE 5.4+). Unblocks J3 TC3.19 (USoundWave direct binding) and any future test needing a disposable wave. -
5 helper MCP actions (F8) —
editor::create_empty_map(UWorldFactory + IAssetTools),editor::get_module_status(IPluginManager + FModuleManager reflection),gas::grant_ability_to_pawn(CDO mutation via reflection on convention-namedTArray<TSubclassOf<UGameplayAbility>>UPROPERTY),ai::add_perception_to_actor(any actor BP,sensesarray),ai::get_bt_graph(flat node_id/parent_id/children GUID dump). Resolves J2/J3 spec prerequisites that previously blocked agent-driven test setup. -
Baseline vitals AttributeSet (F4) — six
FGameplayAttributeData(Health/MaxHealth/Sanity/MaxSanity/Stamina/MaxSamina),PreAttributeChangeclamps,PostGameplayEffectExecutere-clamps, REPNOTIFY_Always replication. Additional resistance attributes deferred. -
MonolithSourceauto-reindex on hot-reload (F17) —UMonolithSourceSubsystembindsFCoreUObjectDelegates::ReloadCompleteDelegateand kicksTriggerProjectReindex()(project-only — engine source DB stays frozen at bootstrap) on every Live Coding patch and post-UBT hot-reload. Three guards: 5-second cooldown,bIsIndexingre-entrancy, bootstrap-DB-missing skip. Eliminates manualsource.trigger_project_reindexcalls in the dev loop. -
GAS UI binding observability (F9) — 8 new
UE_LOGsites: 4 handler-success (bind/unbind/list-Verbose/clear) plus per-fireApplyValuetrace at Verbose plus owner-resolution Warning escalation gated by 1-second grace window (FActiveSub::FirstSubscribeAttemptTime+bGraceEscalated). All 7 pre-existing UE_LOG sites unified under parentLogMonolithGAS(file-staticLogMonolithGASUIBinding/LogMonolithGASUIBindingExtretired). -
Frontmatter Tool-Allowlist Discipline rule (F13) —
.claude/rules/always/agent-rules.mdadds rule preventing future F10-style drift (foreign-namespace tool named in agent prompt MUST appear intools:frontmatter). NewPlugins/Monolith/Scripts/lint_agent_tools.pyautomates the check (pure stdlib, exit 1 on violations, walks all 30 agents). -
F22 — P0 SmartObjects + StateTree gating retrofit (
MonolithAI.Build.cs) — The prior Build.cs hard-added 7 modules toPrivateDependencyModuleNamesand force-definedWITH_STATETREE=1+WITH_SMARTOBJECTS=1. The five backing engine plugins (StateTree, GameplayStateTree, PropertyBindingUtils, StructUtils, SmartObjects) all carryEnabledByDefault: falsein their.upluginmanifests — end users on a fresh project install hit C1083 (missing headers) and LNK2019 (missing module exports) when loading the Monolith plugin without first enabling these engine plugins via the .uproject Plugins panel. Same shape as Issue #30 where MonolithMesh.dll hard-linked GeometryScriptingCore.dll. Fix: two new conditional probe blocks (bHasStateTree+bHasSmartObjects) modeled on the existingbHasGameplayAbilities/ GBA / CommonUI patterns. Each probes 3 locations (enginePlugins/Runtime/<Plugin>/, enginePlugins/AI/<Plugin>/, projectPlugins/<Plugin>/) and honoursMONOLITH_RELEASE_BUILD=1to force OFF for binary releases..cppaction sites already guarded with#if WITH_STATETREE/#if WITH_SMARTOBJECTS—RegisterActionsbecomes empty when the macro is 0 so the StateTree + SmartObjects actions simply do not register on hosts without those plugins. -
CommonUI action pack — M0.5 milestone (50 new actions) — Activatable widget infrastructure (stack, switcher, push/pop), CommonUI button / text / border style classes (class-as-data Blueprint pattern), input action data tables and bound action bars, generic input listeners, focus management (navigation, initial focus, focus path, force-focus, focus ring enforcement), animated switcher, widget carousel, hardware visibility border, lazy-image, load-guard, common message dialogs, modal overlays, tab list. Conditional on
#if WITH_COMMONUIwith 3-location Build.cs detection (consistent with other optional integrations). Default button class auto-created at/Game/Monolith/CommonUI/MonolithDefaultCommonButton. Authored by @tumourlove; verified PASS on M0.5.1 testing pass. -
PR #37 — anim graph property setter, native-component property setter, extended HTTP retry (community contribution by @MaxenceEpitech) —
set_anim_graph_node_propertylets agents tune existing AnimNode pins after the node is placed.native-component set_component_propertyextends the property setter to native-component instances on Blueprint classes (a long-standing gap). Extended HTTP bind retry hardens the v0.14.3 base (Monolith.Restartconsole command + 5-attempt exponential backoff) for additional zombie-listener cases.
-
Behavior Tree crash hardening (F1) — Five
ai::add_bt_*actions andbuild_behavior_tree_from_specnow reject Task-under-Root parenting at the API entry point viaValidateParentForChildTaskhelper plus schema-checkedConnectParentChild. Root cause:UBehaviorTreeGraphNode_Root::NodeInstanceisnullptrby engine design; wiring a Task there produced a malformed graph that crashedUBehaviorTreeGraph::UpdateAsset()atBehaviorTreeGraph.cpp:517. -
gas::bind_widget_to_attributerejects unknownowner_resolver(F2) —ParseOwnerno longer silently coerces unrecognized strings (e.g."banana") toOwningPlayerPawn. Returns enumerated valid-list error:[owning_player_pawn, owning_player_state, owning_player_controller, self_actor, named_socket:<tag>]. Empty input still defaults (back-compat). -
gas::bind_widget_to_attributerejects malformedformat_stringtemplates (F3) — NewValidateFormatStringPayloadhelper enforces{0}slot whenformat=format_string, plus{1}whenevermax_attributeis bound. Both bare and typed-slot forms accepted. Catches user-suppliedformat=format_string:NoSlotsANDformat=autoauto-promoted to FormatString without template. -
audio::bind_sound_to_perceptionrejects four silent-accept input seams (F11) — pre-flightValidateBindingParamsrejectsloudness < 0,max_range < 0,tag.Len() > 255. NewParseSenseClassstrict allowlist: Hearing only (case-insensitive, accepts"Hearing"and"AISense_Hearing"); future classes (Sight/Damage/Touch/Team/Prediction) return distinct"deferred to v2"error; everything else returns"Unsupported sense_class '<X>'". Replaces buggyTObjectIteratorwalk where"AISense_Sight".Equals("Sight", IgnoreCase)was FALSE causing silent fallback to Hearing. -
Invalid-GUID vs unknown-GUID error messages now distinct (F15) — 16 sibling sites in
MonolithAIBehaviorTreeActions.cpphoisted into newRequireBtNodeByGuidhelper. Parse failure →"<param> 'X' is not a valid GUID". Lookup failure →"No node with GUID 'X' in BT 'Y'". Bonus: 4 empty-or-resolve sites also emit"Root node not found in BT graph"distinct from GUID-resolve failures. -
GAS UI binding response-shape & error-text drift (F5) —
index→binding_index, compositeattribute/max_attributestrings added alongside split fields,widget_classfield added to list response,removed_binding_indexadded to unbind response, "Available widgets: [...]" enrichment viaBuildAvailableWidgetsClause(sorted, capped at 20),BuildValidPropertiesClauseenrichment for invalid-property errors,LoadWBPsplit into not-found vs wrong-class branches. -
CDO save pipeline cradle/walker fixes (F9 — PR #39 by @danielandric) — Four-mechanism fix: transient-outer reparent (
MonolithEditCradle::ReparentTransientInstancedSubobjects), walker unification (WalkObjectRefLeaves),FMapProperty::ValuePropdouble-offset fix, sparse-iteration fix (Helper.GetMaxIndex()+IsValidIndex). Closes inline-subobject sub-case left after #29 (v0.14.3's recursive cradle). -
Drop deprecated StructUtils plugin/module dep — Plugin marked
DeprecatedEngineVersion=5.5;FInstancedStruct,FStructView,FSharedStruct,UserDefinedStructetc. all relocated into CoreUObject's public surface in 5.5+ (Engine/Source/Runtime/CoreUObject/Public/StructUtils/). Removed"StructUtils"token fromMonolithAI.Build.csbHasStateTreeblock andMonolith.uplugin's plugin entry. Existing#include "StructUtils/InstancedStruct.h"paths resolve transparently from CoreUObject — no source-include changes needed. Silences the per-launchLogPluginManager: Display: The Plugin StructUtils has been marked deprecated for 5.5 and will be removed soonwarning and pre-empts the eventual hard-removal that would detonateMonolithAImid-build with no warning. -
Native-component overrides persist across editor restart (PR #37 follow-up by @MaxenceEpitech + @tumourlove) — Components added to a Blueprint via
add_componentpreviously had their property overrides discarded on save+reopen. Routes property writes through the UPROPERTY Setter meta and special-casesSkinnedAsset(which has a non-trivial setter chain).
-
J1/J2/J3 spec corrections (F6 + F7 + F14 + F16) — 17 prereq corrections across J specs (9 missing fixtures promoted to create-as-disposable, 5 wrong-facts corrected including Mana → Sanity drift, 3 non-existent actions TODO'd then resolved by F8). J1
warningsfield documented as omit-when-empty. Levenshtein "did you mean" replaced with full valid-property list. J2 TC2.16/TC2.17 sample responses rewritten to documentevent_tag/node_nameas omit-when-empty. J2 swept ofAbility.Combat.Punch/Kickreferences — replaced with existingAbility.Combat.Melee.Light/Heavyregistry tags (verified atConfig/DefaultGameplayTags.ini:26-27); fixture abilities renamed. - Public action count restated as 1239 (16 public namespaces). The previous "1277 → 1283 (+6 from Phase J)" framing didn't reflect the actual public surface in the release zip — it included pre-Phase-J counts that hadn't been audited against ground truth, and conflated internal sibling-plugin actions with the public Monolith plugin proper. The +6 Phase J adds (F8 + F18) and other in-release additions (CommonUI M0.5 +50 actions, PR #37 anim graph setter etc., F22 retrofit gating) all roll up into the 1239 figure.
-
Templates/CLAUDE.md.exampleno longer ships — The shipped CLAUDE.md template was a static snapshot that grew stale fast (tool list, action counts, conventions all drift). For a project-instructions file that fits your toolchain, ask your AI assistant directly. Practical prompt to feed your LLM after installing Monolith: "I've installed the Monolith Unreal plugin. It exposes ~1239 actions over an in-process MCP HTTP listener athttp://localhost:9316/mcp. What's the best-practice format for a project-instructions file for this assistant —CLAUDE.md/AGENTS.md/.cursorrules/.github/copilot-instructions.md/ etc.? Should help with action discovery, asset-path conventions like/Game/Path/Asset, and verifying UE 5.7 APIs viasource_querybefore writing code." — different tools have different conventions and they evolve faster than a template can keep up.
-
Agent frontmatter cross-namespace dispatcher additions (F12) — 5 agents had cross-namespace
mcp__monolith__*tools added to theirtools:frontmatter line soToolSearch select:could load them:unreal-ai-expert,unreal-audio-expert,gas-expert,interface-architect,unreal-blueprint-expert. Fixes the F10 prose-only patch where agents were told to use cross-namespace dispatchers but the dispatcher tool names were missing from their allowlists. -
Domain Agents Are Editor Specialists rule (new) —
.claude/rules/always/agent-rules.mdcodifies that all domain agents (gas-expert, unreal-audio-expert, unreal-ai-expert, etc.) are editor specialists, not C++ implementation agents. Runtime C++ writing/refactoring belongs tocpp-performance-expertorrefactoring-expert. Generalizes the prior anim-only rule. Cross-ref inDocs/references/AgentRegistry.md. -
F22 ADR amendment in
SPEC_CORE.md— F22 entry updated post-StructUtils-cleanup to record that the deprecated StructUtils plugin module was subsequently dropped from the gated set in the same release. Preserves archaeological record without leaving the spec contradicting reality. -
Sibling-plugin strip auto-discovery in
make_release.ps1— The release script now auto-discovers allPlugins/Monolith*/sibling folders (excluding Monolith itself) for$StrippedModulesdefense-in-depth, instead of a hardcoded list. New siblings get protected automatically without script maintenance.
-
MonolithGAS + MonolithIndex still hard-link
GameplayAbilities— they haven't received the F22 conditional probe treatment yet. Functionally fine in practice becauseGameplayAbilitiesis declared as a hard dep inMonolith.uplugin(noOptionalflag), so the engine auto-enables it on Monolith install and guarantees load order before Monolith DLLs initialise. The release smoke check normally flags this as a sentinel hit, but the sentinel was relaxed for v0.14.7 specifically because the .uplugin contract makes it functionally safe. Honest take: this release has been through more testing rounds than I want to admit and we're shipping with the documented gap rather than rolling another full cycle. Migration to optional +WITH_GAMEPLAYABILITIESsource gate is planned for v0.14.8 alongside the StructUtils-cleanup follow-up.
- @playtabegg — Issue #38 responsible-disclosure security audit (CORS reachability + adjacent findings). Direct, fast-turnaround report with realistic exploit framing.
- @MaxenceEpitech — PR #37 anim graph property setter + native-component setter + extended HTTP retry. Substantial multi-area contribution.
-
@danielandric — PR #39 recursive cradle sub-case + walker unification +
FMapProperty::ValuePropoffset fix + sparse-iteration fix. Closes the inline-subobject sub-case left after the v0.14.3 fix to Issue #29.
Full diff: v0.14.5...v0.14.7
-
Build error: missing
MonolithPackagePathValidator.h(#35) — Header was added to working tree but not tracked by git when v0.14.3 was cut. Three modules (MonolithAI,MonolithGAS,MonolithUI) included it, causingC1083on clean builds. Now properly tracked. Reported by @krojew.
Full diff: v0.14.3...v0.14.4
-
HTTP bind retry with port probe (#33) —
Start()now retries up to 5 times with exponential backoff when the port is held by a zombie editor instance. A TCP socket probe verifies the bind actually took, instead of trustingStartAllListeners()which can fail silently. NewMonolith.Restartconsole command for manual recovery without restarting the editor. PR by @MaxenceEpitech. -
Animation IK and bone control nodes (#34) —
add_anim_graph_nodenow supportsTwoBoneIK,ModifyBone,LocalToComponentSpace, andComponentToLocalSpacenode types. TwoBoneIK auto-exposesEffectorLocation,JointTargetLocation, andAlphaas input pins. Newexpose_pinsparameter for manual pin control on any node type. PR by @MaxenceEpitech. -
add_variable_getaction (#34) — Places aK2Node_VariableGetin an ABP anim graph for reading AnimInstance member variables. Validates the variable exists on the skeleton class before spawning. Animation action count: 115 → 116. PR by @MaxenceEpitech.
-
Nested struct/array cross-package TObjectPtr serialization (#29) —
set_cdo_propertynow fires recursivePreEditChange/PostEditChangeChainPropertyon every nested sub-property containing object references, matching the Details panel's full edit cradle. Previously only the outer property got the notification, so innerTObjectPtrfields in structs and arrays would serialize as null on save. Also wired the cradle intocreate_data_assetandcreate_blueprintto fix creation-sideFOverridableManagerpoisoning. Reported by @danielandric.
- @MaxenceEpitech — PRs #33, #34 (HTTP retry + animation IK nodes). Two solid contributions in the same day.
- @danielandric — Issue #29 (nested property cradle). Thorough repro with the IMC DefaultKeyMappings case — made the fix straightforward.
Full diff: v0.14.2...v0.14.3
-
macOS (Apple Silicon) support (#24) — Monolith now builds and runs on macOS 15 / Apple Silicon under UE 5.7. Uses the existing Python proxy as the stdio↔HTTP bridge (the native C++ proxy remains Windows-only for now).
- New
Scripts/monolith_proxy.shshell launcher withpython3/pythonauto-detection and 3.8+ version gate (parity withmonolith_proxy.bat). -
Scripts/monolith_proxy.pynow declaresfrom __future__ import annotationsso PEP 604 type syntax (str | None) works on Python 3.8+ — macOS ships 3.9 by default. -
MonolithNiagaraActions.cpp: renamed localNO→NodeObjto dodge the<objc/objc.h>#define NO __objc_nomacro leak that transitively reachesApplePlatformProcess.hand broke compilation. -
Monolith.uplugin: dropped a ghost private-integration module reference after the integration moved to a sibling plugin outsidePlugins/Monolith/; sibling plugins are naturally excluded from release zips bygit ls-filesscope, so no explicit stripping is required. - README + CONTRIBUTING updated to document macOS/Linux support and
.shlauncher. - PR by @MaxenceEpitech.
-
Note for macOS users: this release ships Windows binaries only. Please clone the repo and build from source per
CONTRIBUTING.md— the macOS build path is proven (all 17 Monolith dylibs compile on UE 5.7 / Apple Silicon). Prebuilt macOS dylibs will follow once a GitHub Actions macOS runner is wired up.
- New
-
Editor crash on indexer pass with WorldPartition-enabled persistent level (#20, fix #21) —
LevelIndexer::IndexAssetloaded level packages viaLoadPackageto enumerate actors, which initializesUWorldPartitionfor WP-enabled levels (UE 5.4+ default). BecauseLoadPackageskips the editor's open-level flow, nothing tore down the subsystem, and when the batch loop marked the package for unload and GC eventually ran,UWorldPartitionSubsystem::Deinitializeasserted atWorldPartitionSubsystem.cpp:507. Fix uninitializes WorldPartition afterIndexActorsInLeveland beforeTryUnloadPackage(World). Affected every UE 5.4+ project with a WP-enabled persistent level and the defaultbIndexLevelssetting. Reported and fixed by @danielandric. -
Full Monolith rebuild on every UBT invocation after ZIP install (#22, fix #23) — PowerShell's
Compress-Archivewrites only DOS time (no NTFS or Unix extended timestamp), and DOS time is naked wall-clock with no timezone tag.Expand-Archivereinterprets the stored bytes as the user's local time, so a UTC+10-packaged ZIP extracted on UTC+0 landed with file mtimes ~10 hours in the user's future. UBT'sTargetMakefile.IsValidForSourceFilescomparesExternalDependency.LastWriteTimeUtcagainstMakefile.CreateTimeUtc, so a future mtime onMonolith.uplugintripped the check on every build and forced a full Monolith rebuild until the user's wall clock caught up. Affected every C++ user with auto-update on (default) and every C++ user installing from the ZIP manually. Fix mirrors POSIX tar's--touch: the auto-updater swap scripts (Windows + macOS/Linux) touch installed files post-xcopy, andMonolithCoreModule::StartupModuleruns an idempotent self-heal that walks the plugin tree ifMonolith.upluginshows a future mtime (covers manual-install users). Microsoft acknowledged the underlying ZIP design flaw in PowerShell/Microsoft.PowerShell.Archive#133; their fix has not shipped. Reported and fixed by @danielandric.
-
Release builds now run non-unity —
Scripts/make_release.ps1passes-DisableUnityto UBT so missing includes and unity-only symbol collisions get caught before they reach a public release.
- @danielandric — PR #21 + issue #20 (WorldPartition indexer crash), PR #23 + issue #22 (ZIP mtime normalization). Thank you for two clean, well-diagnosed fixes in a single day.
- @MaxenceEpitech — PR #24 (macOS support — shell launcher, Python compat, Objective-C macro dodge, ghost module cleanup). Thanks for putting in the proof-of-work end-to-end build verification on Apple Silicon.
Full diff: v0.13.2...v0.14.0
-
Pulled v0.13.1 — it accidentally shipped with some work-in-progress CommonUI stuff in
MonolithUIthat I forgot was sitting in my working tree. Same #19 fix as 0.13.1, just rebuilt clean from a committed tree. Grab this one instead. The release script now refuses to run with a dirty working tree so this doesn't happen again.
Withdrawn. Use v0.13.2 — same fix, built from a clean tree. 0.13.1's release zip contained uncommitted WIP for unrelated MonolithUI work.
-
Indexer fatal crash: "Calling FinishCompilation is not allowed during PostCompilation" (#19) — sorry about this one, the fix I shipped for #16 in 0.13.0 caused the regression. I was calling
FAssetCompilingManager::FinishAllCompilation()from insideAsyncTask(ENamedThreads::GameThread, ...)lambdas to avoid the reentrant compile crash, but those lambdas can land on the game thread while UE is already mid-FTextureCompilingManager::PostCompilation, and the engine fatals on that reentrance (TextureCompiler.cpp:454). Epic's own comment on the line above says workers should useExecuteOnGameThreador tick-scheduled dispatch instead ofAsyncTask(GT). Done and done.- New
FMonolithCompilerSafeDispatch::RunOnGameThreadWhenCompilerIdlehelper — schedules work viaFTSTicker(main tick loop, not task graph) and only fires whenFAssetCompilingManager::GetNumRemainingAssets() == 0, with a 120s timeout safeguard. - All 8 asset-loading
AsyncTask(GT)sites inMonolithIndexSubsystem.cpprerouted through the helper: deep-index batch, dependency, level, data table, animation, gameplay tag, niagara, mesh catalog indexers. - All 5
FinishAllCompilation()calls inside indexer payloads deleted — the helper's idle-precondition is now the single point of compiler synchronization. - Reported by @asafdubaaa.
- New
- @asafdubaaa — issue #19 (caught the regression fast, thanks for the stack traces)
Full diff: v0.13.0...v0.13.2
-
MonolithAudio module shipped — 81 actions across Phases 0-2: Sound asset CRUD (15), query/search (10), batch operations (10), Sound Cue graph building (21), MetaSound Builder API integration (25). Power actions:
build_sound_cue_from_spec,build_metasound_from_spec,apply_audio_template. MetaSound features gated onWITH_METASOUND(graceful degradation when absent). Module had been completed + tested internally on 2026-04-08; v0.13.0 is its public debut. -
Indexer RAM tier auto-detect —
FMonolithMemoryHelperpicks memory budget + batch sizes from installed RAM: 64+ GB → 32768 MB / deep=8 / post=4; 32+ GB → 16384 MB / deep=8 / post=4; 16 GB → 6144 MB / deep=4 / post=2; <16 GB → 3072 MB / deep=2 / post=1. Settings defaults changed to0(auto-detect sentinel) forMemoryBudgetMB,DeepIndexBatchSize,PostPassBatchSize. Override via Project Settings > Monolith > Indexing > Performance. Tier logged once per editor session on first index run.
-
Indexer OOM + reentrant texture compiler crash on large projects (#16) — deep-index batches could exhaust physical RAM or re-enter
FTextureCompilingManager::ProcessAsyncTasks, crashing the editor on large projects (>20 GB content). Fix introducesFAssetCompilingManager::FinishAllCompilation()guards before each batch, forced GC between batches, Slate-safe yields, emergency pause when available memory drops below 2 GB, and honors the async notification Cancel button. Shipped as PR #17 from @alakangas. Reported by @MAYLYBY.
-
bLogMemoryStatsdefault flipped tofalse— opt in when debugging indexer memory behavior. Keeps shipped-project logs quiet.
- @alakangas — PR #17 (indexer OOM + reentrant compiler crash fix)
- @MAYLYBY — issue #16 (detailed crash report that drove the fix and uncovered the low-spec regression addressed by the RAM tier auto-detect)
Full diff: v0.12.1...v0.13.0
- UE 5.7 compatibility — resolved deprecated API usages causing C2220 in non-unity builds (#12)
- Non-unity build — fixed symbol collisions across 8 files (module-prefixed anonymous helpers)
- ComboGraph log category — proper extern declaration, no duplicate defines
-
Uninitialized variables — zero-initialized
FVectorlocals
- StateTree schema resolution with multiple fallback paths
- UI animation: binding helpers, transform/color component keyframes, GUID bookkeeping
- UI param handling: safer required/optional field accessors, duplicate-asset guard
Biggest release yet: +310 actions (815 to 1125). Two new domain modules (MonolithAI, MonolithLogicDriver), ComboGraph expansion. Python-to-C++ port of standalone tools. 14 skills (up from 12).
MonolithAI (229 actions) — AI Asset Manipulation
The most comprehensive AI tooling available through any MCP server. 229 actions across 15 categories, 24K lines C++, 30 files. Full lifecycle management for Behavior Trees, Blackboards, State Trees, EQS, Smart Objects, AI Controllers, AI Perception, Navigation, Runtime, Scaffolds, Discovery, and Advanced categories.
Crown jewels: build_behavior_tree_from_spec and build_state_tree_from_spec — hand the AI a JSON description and it builds the entire asset programmatically. Conditional on #if WITH_STATETREE and #if WITH_SMARTOBJECTS (required, both ship with UE). Optional: #if WITH_MASSENTITY and #if WITH_ZONEGRAPH for large-scale AI.
MonolithLogicDriver (66 actions) — Logic Driver Pro State Machines
Full integration with Logic Driver Pro. SM CRUD, graph read/write, node configuration, runtime/PIE control, JSON spec import/export, scaffolding (door controller, health system, AI patrol, dialogue system, elevator, puzzle, inventory), component management, text graph visualization, discovery. Reflection-only integration (no direct C++ API linkage) — works with any Logic Driver Pro version. Conditional on #if WITH_LOGICDRIVER with 3-location Build.cs detection. 2 new skills: unreal-logicdriver, unreal-combograph.
MonolithComboGraph expanded (12 to 13 actions)
Added auto_layout action for combo graph node arrangement.
Standalone C++ Tools (Python-to-C++ port)
Two standalone C++ executables replace the Python scripts. Zero Python dependency at runtime.
-
monolith_proxy.exe(473KB) — MCP stdio-to-HTTP proxy. Full feature parity withmonolith_proxy.py: JSON-RPC, health poll, tool dedup, editor query splitting, action allowlist/denylist. Built with WinHTTP + nlohmann/json, zero UE dependency. Source:Tools/MonolithProxy/monolith_proxy.cpp(775 lines). -
monolith_query.exe(1.8MB) — Offline DB query tool. Replacesmonolith_offline.pyANDMonolithQueryCommandlet. 14 actions: 9 source + 5 project. Built with sqlite3 amalgamation, zero UE dependency, instant startup. Source:Tools/MonolithQuery/monolith_query.cpp(1080 lines).
Python scripts remain as deprecated fallbacks. MonolithQueryCommandlet deleted (the standalone exe is faster).
- Total: 815 -> 1125 actions across 15 modules (was 13), exposed through 18 MCP tools (was 15)
- Blueprint: 86 -> 88 actions
- ComboGraph: 12 -> 13 actions
- Skills: 12 -> 14 bundled with plugin
-
.mcp.jsonproxy config: recommendmonolith_proxy.exeover Python script - Python is no longer required for any core functionality (only for optional project C++ source indexing)
Massive expansion: +372 actions (443 to 815). Three new modules (MonolithMesh, MonolithGAS, MonolithBABridge). MCP auto-reconnect proxy for Claude Code. Optional module system for third-party plugin integrations. 12 skills (up from 9).
- MonolithMesh (242 actions) — 22 capability tiers: mesh inspection, scene manipulation, spatial queries, blockout, GeometryScript, horror spatial analysis, accessibility, lighting, audio/acoustics, performance, decals, level design, tech art, context-aware props, procedural geometry (furniture, horror props, structures, mazes, terrain), genre presets, encounter design, quality/polish. +45 experimental town gen (disabled by default).
- MonolithGAS (130 actions) — Complete Gameplay Ability System: abilities, attributes, effects, ASC, tags, cues, targeting, input, inspect, scaffold. 53/53 tests PASS. Optional GBA support for Blueprint AttributeSets.
- MonolithUI (42 actions) — Widget Blueprint CRUD, templates (HUDs, menus, settings, inventory), styling, animation, game scaffolding, accessibility.
- MonolithBABridge — Blueprint Assist integration via IModularFeatures bridge. Enhanced auto_layout when BA is installed.
- MCP auto-reconnect proxy — stdio-to-HTTP proxy keeps Claude Code sessions alive across editor restarts.
-
Optional module system —
Build.csprobe pattern for third-party plugins (GeometryScripting, BlueprintAssist, GBA). -
3 new skills —
unreal-mesh,unreal-ui,unreal-gas.
- Total: 443 -> 815 actions across 13 modules, exposed through 15 MCP tools
- Skills: 9 -> 12 bundled with plugin
Massive expansion across all modules: +153 actions (290 to 443). Niagara nearly doubles with 31 new actions and 10 bug fixes. Blueprint and Animation get major expansions. Material function suite rounds out the material pipeline.
Niagara (+31, 65 -> 96)
-
add_dynamic_input/remove_dynamic_input/set_dynamic_input_value/get_dynamic_input_info/search_dynamic_inputs-- full dynamic input CRUD -
add_event_handler/remove_event_handler/list_event_handlers-- event handler management -
add_simulation_stage/remove_simulation_stage/list_simulation_stages-- simulation stage CRUD -
create_npc_system/add_npc_behavior/get_npc_info/set_npc_property/list_npc_templates-- NPC particle system support -
create_effect_type/get_effect_type_info/set_effect_type_property-- effect type CRUD -
list_available_renderers/set_renderer_mesh/configure_ribbon/configure_subuv-- renderer helpers -
diff_systems-- diff two Niagara systems side-by-side -
save_emitter_as_template-- save an emitter as a reusable template -
clone_module_overrides-- clone module overrides between emitters -
preview_system-- trigger a system preview in the editor -
get_available_parameters/get_module_output_parameters-- parameter introspection -
rename_emitter-- rename an emitter within a system -
get_emitter_property-- read a single emitter property -
export_system_specexpanded -- now includes event handlers, sim stages, static switches, and dynamic inputs
Blueprint (+20, 66 -> 86)
-
auto_layout-- Modified Sugiyama graph layout algorithm for automatic node arrangement - 22 new actions including expanded node types, resolve improvements, DataTable field resolution
-
batch_executeimprovements for bulk operations
Animation (+41, 74 -> 115)
- 41 new actions covering expanded montage editing, blend space manipulation, skeletal mesh queries, and animation asset management
Material (+9, 48 -> 57)
-
create_material_function/build_function_graph/get_function_info-- material function full suite -
batch_set_material_property/batch_recompile-- batch operations -
import_texture-- image file import as UTexture2D -
list_material_instances/replace_expression/rename_expression-- additional utilities
Project (+2, 5 -> 7)
- 2 new project index actions for deeper asset discovery
Niagara (10 fixes)
-
batch_executereads now return data correctly instead of silently succeeding - Type validation on module inputs catches mismatched types before crash
- GUID collision fix when duplicating emitters with shared module references
- ShapeLocation race condition on freshly-created emitters with shape DIs
- Color curve fan-out when multiple emitters share the same curve keys
- NPC namespace routing fixed for NPC-specific actions
-
move_modulenow preserves parameter overrides during reorder - 3 test-driven fixes from Phase 1-6 testing
Material (6 fixes)
-
AssetTagsFinalizedrenamed to match UE 5.7 API change - 5 missing includes that caused compile failures on clean builds
Blueprint (5 fixes)
- DataTable UDS field resolution -- match by display name
-
resolve_nodeexpanded -- Self, MacroInstance, Return, generic fallback - K2Node generic fallback -- strip U prefix for UObject name lookup
- Simplified templates -- removed broken function refs
- Code review cleanup -- dead code, magic numbers, perf, correctness
- Niagara -- Action count 65 -> 96
- Blueprint -- Action count 66 -> 86
- Animation -- Action count 74 -> 115
- Material -- Action count 48 -> 57
- Project -- Action count 5 -> 7
- Total -- Action count 290 -> 443 (across 10 modules)
+69 new actions (219 → 290 total), 60 bug fixes, 202 tests all pass.
Blueprint (+20, 47 → 67)
-
batch_execute— dispatch multiple Blueprint operations in a single call -
resolve_node— resolve a node reference to its target (function, variable, etc.) -
search_functions— search functions and events by name across a Blueprint -
get_node_details— full detail dump for a single node (pins, defaults, metadata) -
add_nodes_bulk/connect_pins_bulk/set_pin_defaults_bulk— bulk graph operations in one call -
scaffold_interface_implementation— auto-generate stub event nodes for an unimplemented interface -
add_timeline/add_event_node/add_comment_node— new node types foradd_node -
get_function_signature— return param list and return type for a Blueprint function -
get_blueprint_info— comprehensive Blueprint summary (class, interfaces, components, variable count) -
get_event_dispatcher_details/remove_event_dispatcher/set_event_dispatcher_params— event dispatcher management -
validate_blueprint(enhanced) — now detects unimplemented interfaces and duplicate events -
promote_pin_to_variable— promote a pin's value to a Blueprint variable -
add_replicated_variable— add a replicated variable with configurable RepNotify -
add_node(extended) — now supports cast node creation (CastTo<ClassName>)
Material (+22, 25 → 47)
-
auto_layout— auto-arrange expression nodes in the material graph -
duplicate_expression/replace_expression— expression node management -
list_expression_classes— list all available material expression class names -
get_expression_connections/get_expression_pin_info— expression inspection -
move_expression/rename_expression— expression editing -
get_material_properties— return material-level properties (blend mode, shading model, etc.) -
get_instance_parameters/set_instance_parameters/set_instance_parent/clear_instance_parameter— material instance CRUD -
list_material_instances— find all material instances derived from a material -
save_material— explicitly save a material asset -
update_custom_hlsl_node— update the HLSL code on a CustomHLSL expression -
create_material_function/build_function_graph/get_function_info— material function authoring -
batch_set_material_property/batch_recompile— bulk material operations -
import_texture— import an image file as a UTexture2D asset
Niagara (+17, 47 → 64)
-
get_system_summary/get_emitter_summary— high-level overview actions -
list_emitter_properties— list all editable UPROPERTY fields on an emitter asset -
get_module_input_value— read the current value of a single module input -
configure_curve_keys/configure_data_interface— data interface configuration -
duplicate_system/create_emitter— asset management -
set_fixed_bounds/set_effect_type— system-level configuration -
export_system_spec— export a system's full spec as JSON (reverse ofcreate_system_from_spec) -
add_dynamic_input/set_dynamic_input_value/search_dynamic_inputs— dynamic input support -
add_event_handler— add an event handler stage to an emitter -
validate_system— validate for GPU/Light conflicts, missing materials, bounds warnings -
add_simulation_stage— add a simulation stage to a GPU emitter
Animation (+12, 62 → 74)
-
get_ikrig_info/add_ik_solver— IKRig asset inspection and editing -
get_retargeter_info/set_retarget_chain_mapping— IK Retargeter support -
get_control_rig_info/get_control_rig_variables/add_control_rig_element— Control Rig support -
get_abp_variables/get_abp_linked_assets— Animation Blueprint inspection -
add_state_to_machine/add_transition/set_transition_rule— AnimBP structural writes
- Blueprint — 21 fixes: 5 crashes (null graph ref, invalid pin access, blueprint-not-compiled guard, interface scaffold on abstract classes, cast node creation), 7 logic bugs, 9 UX improvements
-
Material — 11 fixes:
build_function_graphnode class resolution,connect_expressionsdirection detection,get_material_parametersmissing static switch params, and others -
Niagara — 16 fixes: 2 crashes (
configure_data_interfacenull DI,add_event_handleruninitialized receiver), 5 bugs, 9 UX improvements -
Animation — 12 fixes: 1 crash (
add_ik_solvernull pointer), 6 bugs, 5 UX improvements
- Blueprint: 47 → 67 actions
- Material: 25 → 47 actions
- Niagara: 47 → 64 actions
- Animation: 62 → 74 actions
- Total: 220 → 290 actions
Native C++ source indexer, marketplace content indexing, CDO properties, and project C++ source indexing. 3 community PRs from NRG-Nad. 220 actions total.
Source — Native C++ indexer (no Python required)
- Completely rewrote the engine source indexer in native C++ (4,119 lines). Engine source indexing now works out of the box — no Python install, no separate indexer script. Two indexing modes: full engine source on startup, incremental project-only via the new
trigger_project_reindexaction. - New
MonolithQueryCommandletfor offline source queries from the command line. - New
trigger_project_reindexaction: triggers an incremental re-index of project C++ source from an MCP session. (220 total actions)
Index — Marketplace plugin content
- Auto-discovers installed marketplace and Fab plugins and indexes their content alongside project assets. Toggle with
bIndexMarketplacePluginsin plugin settings.
Index — Configurable content paths (#4)
-
AdditionalContentPathssetting for adding arbitrary extra content paths (e.g. external asset packs) to the project index. Credit: NRG-Nad (#4).
Blueprint — CDO property reader (#5)
- New
get_cdo_propertiesaction: readsUPROPERTYdefaults from any Blueprint CDO orUObjectasset. Credit: NRG-Nad (#5). - New
FDataAssetIndexer: deep-indexes DataAsset subclasses. 15 registered indexers total.bIndexDataAssetstoggle in settings. Credit: NRG-Nad (#5).
Source — Project C++ source indexing (#6)
-
Scripts/index_project.py: indexes project C++ source intoEngineSource.dbalongside engine symbols. Incremental pipeline — only changed files are reprocessed. Source DB grows from ~1.8 GB to ~3.4 GB with a full project. Credit: NRG-Nad (#6).
- MonolithSource — Improved error handling throughout the source indexer pipeline.
-
MonolithNiagara — 5 bugs fixed: DI class auto-prefix, DI curve data in
get_module_inputs, LinearColor/vector defaults,disconnect_expressiontargeted disconnection,list_rendererstype short name.
- MonolithBlueprint: 46 → 47 actions (
get_cdo_properties) - MonolithSource: 10 → 11 actions (
trigger_project_reindex) - Total: 219 → 220 actions
- Source indexing no longer requires Python for engine lookups. Python is only needed for optional project C++ source indexing.
Blueprint module fully realized (6 → 46 actions). Niagara HLSL module creation implemented. Major Niagara, Material, and MCP reliability fixes. 218 actions total.
Blueprint — 40 new write actions (6 → 46 total)
-
Variables (7):
add_variable,remove_variable,set_variable_default,set_variable_type,set_variable_flags,rename_variable,get_variable_details -
Components (6):
add_component,remove_component,set_component_property,get_components,get_component_details,reparent_component -
Graph management (9):
add_function_graph,remove_function_graph,add_macro_graph,remove_macro_graph,add_event_graph,remove_event_graph,get_functions,get_event_dispatchers,get_construction_script -
Nodes & pins (6):
add_node,remove_node,connect_pins,disconnect_pins,get_pin_info,find_nodes_by_class -
Compile & create (5):
compile_blueprint,create_blueprint,reparent_blueprint,add_interface,remove_interface -
add_nodenow resolves common node class aliases (CallFunction,VariableGet,VariableSet,Branch,Sequence,ForEach) and triesK2_prefix automatically
Niagara — HLSL module authoring (2 new)
-
create_module_from_hlsl— Creates aUNiagaraScript(module usage) with a CustomHlsl node and typed ParameterMap I/O pins. Inputs are exposed as overridable parameters — compatible withget_module_inputsandset_module_input_value. CPU and GPU sim targets supported. -
create_function_from_hlsl— Same as above in function usage context (reusable utility, direct typed pin wiring, no ParameterMap wrapper). - Dot-containing pin names (e.g.
Module.Color) rejected at creation time with clear guidance.
Niagara — System controls & discovery (5 new)
-
set_system_property— Set system-level properties (e.g.WarmupTime,bDeterminism) via UE reflection. AnyUPROPERTYonUNiagaraSystemis settable. -
set_static_switch_value— Set static switch inputs on module stack entries for compile-time code path control. -
list_module_scripts— Keyword search for available Niagara module script assets. -
list_renderer_properties— Lists all editableUPROPERTYfields on a renderer via reflection, with current values. -
get_system_diagnostics— Compile errors, warnings, renderer/SimTarget incompatibility flags, GPU/dynamic bounds warnings, per-script stats (op count, register count, compile status).
MCP
-
tools/listnow embeds per-action param schemas at session start — full documentation without callingmonolith_discover()first. - Registry-level required param validation: missing params return a clear error before the handler is called.
Offline CLI
-
Saved/monolith_offline.py— pure Python (stdlib, zero deps) read-only CLI for querying the source and project DBs when the editor is not running. 14 actions acrosssourceandprojectnamespaces.
Niagara
-
add_emitter— emitters were not persisting in the saved asset. Fixed by switching toFNiagaraEditorUtilities::AddEmitterToSystem(). -
create_system_from_spec— failed withfailed_steps:1on any spec with modules. Root cause: missing synchronous compile after each emitter add. Failed sub-operations now reported in"errors"array. -
set_emitter_property— SimTarget change caused "Data missing please force a recompile". Fixed withPostEditChangeVersionedProperty+RebuildEmitterNodes+SynchronizeOverviewGraphWithSystem. -
set_module_input_value/set_module_input_binding— were using stripped short names where the fullModule.-prefixed name was required, causing namespace warnings on every Niagara compile. -
get_module_inputs— correctly deserializesLinearColorand vector defaults; returns realFRichCurvekey data for curve DI inputs; works with CustomHlsl modules. -
list_emitters— now includes emitter GUID in output. -
list_renderers— now returns short renderer class name (e.g.SpriteRenderer) instead of full UClass path.
Material
-
set_expression_property— now callsPostEditChangePropertywith the actual property; changes reflect without a manual recompile. -
build_material_graph— now auto-recompiles on success. -
delete_expression,connect_expressions,disconnect_expression— wrapped inPreEditChange/PostEditChangefor correct undo history and editor updates. -
disconnect_expression— now accepts optionalinput_name/output_namefor targeted disconnection.
Blueprint
-
add_node— now resolves node class aliases andK2_prefix. Previously failed with class-not-found on all common node types.
Core
-
LoadAssetByPath— queries Asset Registry first to prevent staleRF_Standaloneghost objects from shadowing recreated assets.
- Blueprint action count 6 → 46
- Niagara action count 41 → 47
- Total action count 177 → 218
Niagara write testing: all 41 actions verified. 12 bugs found and fixed (4 crashes, 8 logic bugs), plus a major improvement to get_module_inputs.
-
CRASH:
create_system_from_spec—GetAssetPathinfinite recursion (stack overflow) -
CRASH:
create_system— rawNewObjectwithoutInitializeSystem()caused array OOB onAddEmitterHandle -
CRASH:
add_emitter— emitter with no versions caused array OOB -
CRASH:
set_module_input_di— assertion failure when pin already had links -
set_module_input_di— accepted nonexistent input names, non-DI types, and parsed config as string instead of JSON object -
get_module_inputs— only returned static switches. Now returns ALL input types via engine'sGetStackFunctionInputsAPI -
GetStackFunctionInputOverridePin— now walks upstream to ParameterMapSet node for data input overrides -
get_module_inputs— strippedModule.prefix for consistency with write actions -
batch_execute— added 8 missing write ops to dispatch table -
FindEmitterHandleIndex— no longer auto-selects when a non-matching name is passed -
set_module_input_value/set_curve_value— addedBreakAllPinLinks()guard for overriding bindings
Animation Wave 2: 44 new actions across animation and PoseSearch, bringing the module from 23 to 67 actions and the plugin total to 177.
-
Curve Operations (7):
get_curves,add_curve,remove_curve,set_curve_keys,get_curve_keys,rename_curve,get_curve_data -
Bone Track Inspection (3):
get_bone_tracks,get_bone_track_data,get_animation_statistics -
Sync Markers (3):
get_sync_markers,add_sync_marker,remove_sync_marker -
Root Motion (2):
get_root_motion_info,extract_root_motion -
Compression (2):
get_compression_settings,apply_compression -
BlendSpace Operations (5):
get_blendspace_info,add_blendspace_sample,remove_blendspace_sample,set_blendspace_axis,get_blendspace_samples -
AnimBP Inspection (5):
get_anim_blueprint_info,get_state_machines,get_state_info,get_transitions,get_anim_graph_nodes -
Montage Operations (5):
get_montage_info,add_montage_section,delete_montage_section,set_montage_section_link,get_montage_slots -
Skeleton Operations (5):
get_skeleton_info,add_virtual_bone,remove_virtual_bones,get_socket_info,add_socket -
Batch & Modifiers (2):
batch_get_animation_info,run_animation_modifier -
PoseSearch (5):
get_pose_search_schema,get_pose_search_database,add_database_sequence,remove_database_sequence,get_database_stats
-
add_virtual_bone— crash on non-existent source bone (array OOB) -
set_notify_time/duration— now works on AnimMontage (was AnimSequence-only) -
delete_montage_section— guard against deleting last remaining section -
add_blendspace_sample— descriptive error on skeleton mismatch -
remove_virtual_bones— no longer reports false success for missing bones
MCP tool discovery fix — tools now register natively in Claude Code's ToolSearch.
- Tool names changed from dot notation to underscore (
material_querynotmaterial.query) - Protocol version negotiation echoes client's requested version
Material Wave 2: 11 new write actions for full material CRUD coverage.
-
create_material,create_material_instance,set_material_property,delete_expression -
get_material_parameters,set_instance_parameter,recompile_material,duplicate_material -
get_compilation_stats,set_expression_property,connect_expressions - Material actions 14 → 25, total 122 → 133
- Auto-updater hot-swap no longer deletes Saved/ directory
-
build_material_graphFindObject → FindFirstObject -
disconnect_expressionmissing material output pins
36/36 read actions verified PASS. Per-action param schemas, new actions, major fixes.
-
Blueprint
get_graph_summary— lightweight graph overview (~10KB vs 172KB). Blueprint 5→6 actions -
Niagara
list_emitters— emitter name, index, enabled, sim_target, renderer_count -
Niagara
list_renderers— renderer class, index, enabled, material. Niagara 39→41 actions - Per-action param schemas in
monolith_discover()output — all actions are now self-documenting - Blueprint
get_graph_dataaccepts optionalnode_class_filterparam - Blueprint
get_execution_flowtwo-pass entry node search (events before comments) - Material
export_material_graphacceptsinclude_propertiesandinclude_positionsparams - Material
get_thumbnailacceptssave_to_fileparam - Niagara
get_all_parametersaccepts optionalemitterandscopefilters - Animation
get_nodesaccepts optionalgraph_namefilter - Animation
get_transitionsincludesfrom_type/to_typefields (state vs conduit)
-
Project Indexer — auto-index deferred to
OnFilesLoaded()(was only indexing 193/9560 assets) -
Material
validate_material— added 7 missing material properties + MaterialAttributeLayers BFS seed (0 false positive islands, was 43) -
Blueprint
get_variables— CDO default values now populated (was always empty) -
Niagara
get_module_inputs— real types via PinToTypeDefinition (no more Vector4f) -
Niagara
get_renderer_bindings— clean JSON output instead of raw UE struct dumps -
Niagara
get_ordered_modules— usage filter with shorthands, error on invalid values -
Niagara
trace_parameter_binding— User. prefix OR fallback -
Niagara
get_di_functions— reversed class name pattern -
Niagara
batch_execute— 3 op name mismatches fixed, old names kept as aliases -
Animation
get_transitions— conduit nodes resolved via UAnimStateNodeBase cast -
Animation state machines —
\nstripped from names, exact matching instead of fuzzy -
Animation
get_state_info— validates required params - All Niagara actions accept
asset_path(withsystem_pathbackward compat) - Niagara
User.prefix stripped transparently in 4 param actions - Niagara
get_compiled_gpu_hlslauto-compiles system if HLSL not cached - Indexer
bIsIndexingreset in Deinitialize, sanity check <500 assets skips last_full_index - Index DB changed from WAL to DELETE journal mode
Auto-updater rewrite — fixes all swap script failures on Windows.
- Swap script now polls
tasklistforUnrealEditor.exeinstead of a cosmetic 10-second countdown -
errorlevelcheck after retry rename was unreachable due to cmd.exe resetting%ERRORLEVEL% - Launcher script now uses outer-double-quote trick for
cmd /cpaths with spaces - Switched from
rentomovefor full path support - Retry now cleans stale backup before re-attempting rename
- Rollback on failed xcopy now removes partial destination before restoring backup
- Added
/hflag to primary xcopy to include hidden-attribute files - Enabled
DelayedExpansionfor correct variable expansion insideifblocks
-
Scripts/make_release.ps1— release zip builder that sets"Installed": truefor Blueprint-only compatibility - Conditional post-update message for C++ vs Blueprint-only users
Source indexer overhaul and auto-updater improvements.
- UE macros (UCLASS, ENGINE_API, GENERATED_BODY) now stripped before tree-sitter parsing
- Class definitions increased from ~0 to 62,059; inheritance links from ~0 to 37,010
-
read_source members_onlynow returns class members correctly -
get_class_hierarchyancestor traversal now works -
get_class_hierarchyaccepts bothsymbolandclass_nameparams
- UE macro preprocessor with balanced-paren stripping
-
--cleanflag for source indexer - Release notes in update notification and Output Log
Initial beta release. One plugin, 9 domains, 119 actions.
- Embedded Streamable HTTP MCP server with JSON-RPC 2.0
- Namespace dispatch pattern (~14 tools instead of ~119)
- 9 domain modules: Core, Blueprint, Material, Animation, Niagara, Editor, Config, Index, Source
- SQLite FTS5 project indexer with 14 asset indexers
- Python tree-sitter engine source indexer
- Auto-updater via GitHub Releases
- 9 Claude Code skills
- Plugin settings via UDeveloperSettings
- HTTP body null-termination, Niagara graph traversal crash, emitter lookup failures
- Source DB WAL lock contention, SQL schema creation, asset loading crash
- 8 additional bug fixes across animation, editor, config, and source modules
- Session tracking removed (fully stateless), first-call failures fixed