Skip to content

LLM Easy Shell ​

TCP shell interface for driving the Unreal Editor from any external client (LLM agent loop, CLI, test harness). One-line commands in, JSON out — no UE editor knowledge required.

Quick value: 37 editor commands · 46 built-in Python abilities · TCP server on ports 15151–15200 · any plugin can host its own abilities · works alongside any LLM agent framework.

🎯 For a minimal-dependency, read-only variant, see LLM Easy Shell Lite (9 commands, 2 engine plugin dependencies, free).


Core Features ​

  • Scene read/write — List, view, spawn, delete, move, rename actors and components
  • Property reflection — set / cat over any UObject, struct, or asset property
  • Asset operations — Browse, create, copy, delete, save assets via /Assets/... paths
  • Function dispatch — call any reflected UFUNCTION on actor or component
  • PIE control — play, stop, pause, gamestate, select, focus
  • Live Coding — livecoding / lc / reload, --restart editor with crash detection
  • Logs — Editor log, error log, compile log, Niagara validation messages
  • UI introspection — uitree / uifind / uiinfo / uipress / uitype / uishot
  • Ability framework — Plugins register C++ commands via RegisterShellCommand() (auto-discovered)
  • PyAbility framework — Drop a .py into any plugin's Content/Python/<Package>/abilities/ to register a command
  • TCP server — Plain text in / JSON out, ports 15151–15200
  • Multi-platform — Win64, Mac, Linux (Live Coding subcommand: Windows only)

Quick Preview ​

bash
# Agent loop — one line per action
> info
{"ok":true,"project":"MyGame","engine":"5.7.4","pie":"stopped","port":15151}

> spawn /Game/Blueprints/BP_Enemy at 100,200,50
{"ok":true,"actor":"/Actor/BP_Enemy_C_42"}

> set /Actor/BP_Enemy_C_42.Health=200
{"ok":true}

> call /Actor/BP_Enemy_C_42.SetActive true
{"ok":true,"result":"activated"}

> uishot
{"ok":true,"file":"Saved/Screenshots/2026-06-15.png"}

Send a one-line command → Get a one-line JSON response. The agent loop never stalls.


Technical Information ​

Features: 37 editor commands (scene read/write, asset read/write, property/function discovery, PIE control, Live Coding, logs, UI introspection, screenshots), TCP server on ports 15151–15200, Ability framework for plugin-registered C++ commands (RegisterShellCommand() / AddPythonAbilityRoot() extension points), PyAbility framework for .py-defined commands hosted by any plugin, 46 built-in Python abilities, command trace logging, and a live Trace Tab window (v1.3.0).

Code Modules: LLMEasyShell (Editor)

Number of Blueprints: 0

Number of C++ Classes: ~115

Network Replicated: No

Supported Development Platforms: Windows: Yes, Mac: Yes, Linux: Yes

Supported Target Build Platforms: Windows, Mac, Linux

Documentation Link: llm-easy-shell skill & reference docs

Example Project: (the public repo ships the skill folder — reference docs and the bundled Python ability set)

Important/Additional Notes: Editor-only plugin. For a minimal-dependency, read-only variant, see LLM Easy Shell Lite. UE 5.5–5.8.


Build Environment ​

Required Host Plugins ​

The following engine plugins must be enabled in the host project before compilation. They are declared in LLMEasyShell.uplugin and the host .uproject must enable each one:

  • PythonScriptPlugin — backs the PyAbility framework and Python-driven abilities (python <name> ...)
  • GameplayAbilities — required by built-in abilities that introspect the Gameplay Ability System
  • GameplayTagsEditor — editor-side gameplay tag inspection
  • EnhancedInput — input mapping queries via discover / cat
  • PoseSearch — Motion Matching database introspection
  • Chooser — Chooser table introspection
  • StructUtils — runtime struct property reflection
  • Niagara — VFX introspection + validation message capture
  • EditorScriptingUtilities — asset registry and editor scripting helpers

Editor-build dependency (host must enable in .uproject):

  • WebBrowserWidget — required at link time for the CEF-state (url / title / page_loaded) block of ui info / uishot. Ships with EnabledByDefault: false; without it the editor target fails to link.
  • ModelContextProtocol (UE 5.8 hosts only) — backs the mcp shell command. Experimental, EnabledByDefault: false. On UE 5.5–5.7 the plugin builds without it and mcp returns a not-available hint.

Verifying a Clean Build ​

bash
cd "/c/Program Files/Epic Games/UE_5.7/Engine/Build/BatchFiles"
./RunUAT.bat BuildPlugin \
  -plugin="D:/path/to/LLMEasyShell.uplugin" \
  -package="D:/Temp/LLMEasyShell" \
  -platform=Win64 \
  -configuration=Development \
  -rocket

The -rocket flag enables Epic's IWYU + ABI-strict build configuration, matching the Fab submission environment. Confirm zero errors and zero consequential warnings (deprecation warnings such as C4996 are treated as errors by marketplace scanners).

UE Version Compatibility ​

  • Minimum: UE 5.5
  • Tested: UE 5.5, 5.6, 5.7, 5.8 (each Fab Project Version ships an engine-matched package)

Command Reference (37 commands) ​

Scene ​

CommandDescription
ls /Level/ActorsList Actors in current level
cat /Actor/{name}View Actor / component / asset details
spawn /Game/.../BP_ActorSpawn actor (class path)
rm /Actor/{name}Delete actor
mv /Actor/{name} 100,200,50Move (Location only)
cp /Actor/{src} /Actor/{dst}Clone actor

Property / Function ​

CommandDescription
set /Actor/{name}.Property=ValueSet any reflected property
call /Actor/{name}.Function arg1Call any UFUNCTION
addcomp /Actor/{name} TypeNameAdd component
discover /Actor/{name} --funcsList available functions
discover /Actor/{name} --propsList properties

Assets ​

CommandDescription
ls /Assets/Browse asset registry
cat /Assets/.../Asset.AssetView asset properties
new /Assets/.../Asset.Asset ClassCreate new asset
cp /Assets/A.A /Assets/B.BDuplicate asset
mv /Assets/A.A /Assets/B.BRename / move asset
rm /Assets/.../Asset.AssetDelete asset
save /Assets/.../Asset.AssetSave modified asset
mkdir /Assets/FolderCreate asset folder

Search / Info ​

CommandDescription
find Actor {pattern}Search Actors by name
find Asset {pattern}Search assets by name
find /Game {pattern}Search assets by path
infoProject + editor + PIE state
gamestatePIE game state summary (reflection-based player / wave stats)
helpList all commands

Editor Control ​

CommandDescription
playStart PIE
stopStop PIE
pausePause / resume PIE
select /Actor/{name}Select Actor in viewport
focus /Actor/{name}Focus camera on Actor
undo / redoEditor undo / redo
saveSave the level

Live Coding / Restart ​

CommandDescription
livecoding / lc / reloadTrigger Live Coding compile
log --compileLast Live Coding compile log
log --restartRestart editor with crash detection

Logs ​

CommandDescription
log --errorsEditor error log
msglog --niagaraNiagara validation messages
livelogTail current editor log

UI Introspection ​

CommandDescription
uitreeDump current UMG widget tree
uifind {pattern}Find UMG widget by name
uiinfo /Widget/{name}Inspect widget properties
uipress /Widget/{name}Simulate click on a button (--root <class> picks the resolution root, v1.3.0)
uitype /Widget/{name} "text"Simulate text input
uishotSlate composite screenshot

Python Abilities ​

CommandDescription
python {name} {args...}Invoke any PyAbility
python reloadRescan abilities/ and clear Python module cache

Python Abilities (46 built-in) ​

LLMEasyShell ships with a reference set of Python abilities in Content/Python/LLMShellAbilities/abilities/. Each ability is a standalone .py module that registers one or more python <name> subcommands.

Drop your own .py into the abilities/ folder, restart the editor (or run python reload), and the ability becomes invocable as python <name>. Any other plugin can host its own ability package the same way — <Plugin>/Content/Python/<Package>/abilities/*.py is discovered automatically; plugin hosts take precedence over the project script directory (ordered by plugin name).

CategoryAbilities
Asset / blueprintasset, blueprint, bpcomp, bpprop, spawn_mesh, mesh_check
Property / reflectionproperty, inspect_subobject_api, dump_rip
Gameplay / playergameplay, get_gamestate, walk_to, set_view_target, unpause
Animation / poseanim, poseseach
Tables / choosersdatatable, chooser
Levels / scene / editorlevel, level_load, editor, editorctl, editor_camera
Materials / VFXcreate_unlit_mat, vfx, vfxsim, bind_niagara_asset, open_niagara_editor, diag_niagara_actor
UIumg
Navigationnavigation
Performanceperf
Test automationrun_automation, automation_check_test, automation_dump_api, automation_list_tests, automation_run_and_wait, automation_sanity_check
Diagnosticsdebug_burst, diag_pie, diag_subsys, pcg_diag, voxel_diag, quixel_table, hd3dscene, list_hd3d_methods

Authoring a New Python Ability ​

python
# <Plugin>/Content/Python/<Package>/abilities/my_ability.py
import unreal
from LLMShellAbilities.registry import Ability, Command
# (inside this plugin's own package, `from ..registry import ...` also works)

class MyAbility(Ability):
    name = "my_ability"
    version = "1.0.0"

    def get_commands(self):
        return [
            Command("my_command", "Does something useful", []),
        ]

    def execute(self, command, args, context):
        if command == "my_command":
            return {"success": True, "output": "..."}
        return {"success": False, "error": "unknown"}


def register(reg):
    reg.register_ability(MyAbility())

Restart the editor or run python reload — the loader scans every enabled plugin for abilities/*.py and calls the module-level register(reg).


TCP Protocol ​

The TCP server speaks a minimal text protocol.

Request ​

Plain ASCII command terminated by \n:

info
ls /Level/Actors
set /Actor/MyActor.Location=100,200,50
python bpprop set BP_Hero.AttackRange=1200

Response ​

Each command returns a single-line JSON object terminated by \n:

KeyTypeMeaning
okboolSuccess / failure
resultanyCommand-specific payload
errorstringHuman-readable error message (only if ok=false)
tracestringOptional command trace id for debugging
json
{"ok": true, "result": {"actor_count": 12, "level": "Lvl_Main"}}
json
{"ok": false, "error": "Actor /Actor/MyActor not found"}

Port Allocation ​

The listener binds to the first free port in 15151–15200. The chosen port is logged at editor startup and recorded in Saved/LLMEasyShell/port.txt.


How to Use ​

  1. Install the plugin to your project's Plugins/ folder.
  2. Enable the 9 engine plugins listed under Required Host Plugins in your project's Plugins browser.
  3. Restart the editor. LLMEasyShell starts a TCP listener on the first free port in 15151–15200.
  4. Connect to the listener from any TCP client to issue commands:
    # Plain TCP — send "info\n" -> receive JSON
    # Or wire it up to an LLM agent that POSTs commands and parses JSON results
  5. To author new C++ commands, derive from ULLMEasyShellAbilityCommandObject and register via the ability registry (auto-discovered at startup).
  6. To author new Python commands, drop a .py into Content/Python/LLMShellAbilities/abilities/ (or your own plugin's ability package) and run python reload.

Trace Tab ​

Every command the shell executes is traced to JSONL under Saved/LLMEasyShell/traces/. Since v1.3.0 you can also watch them live in the editor:

  • LLM Shell Trace tab — a live list of executed commands with a detail pane (Input / Output / Error) for the selected row, a filter box, a failures-only toggle, auto-scroll, and Clear.
  • Opening it — click the port status widget on the Play toolbar (the copy-port action moved to a Copy port button in the tab header). The tab also auto-opens once per editor session when the first traced command arrives; disable with LLMEasyShell.TraceAutoOpen 0. Closing it manually keeps it closed for the rest of the session.
  • C++ data plane — the subsystem keeps a 500-entry in-memory ring buffer (GetRecentTraces(), display-truncated) and broadcasts FOnShellCommandTraced after each command. The JSONL archive remains the full-fidelity record.

Comparison: Easy Shell vs Lite ​

LLMEasyShell ships in two independent variants. They listen on disjoint TCP port ranges and do not conflict at runtime. Install either or both.

LLMEasyShell (this plugin)LLMEasyShell Lite
PurposeFull read + write + automationRead-only exploration
Commands37 (read + write + control)9 (query only)
Python abilities46 built-in abilitiesFramework + 1 demo
ScreenshotsYes (PIE + Win32 paths)No
Live CodingYesNo
TCP port15151–1520015201–15250
Engine plugin deps9 + WebBrowserWidget (+ ModelContextProtocol on UE 5.8)2
CLI binaryllm-shell.exellmshelllite.exe

FAQ ​

Q: Can I use LLMEasyShell on Mac or Linux? Yes — the editor module compiles on Win64, Mac, and Linux. The Live Coding subcommand is Windows-only (UE constraint).

Q: How is this different from LLMEasyShell Lite? Lite is a 9-command, read-only subset on ports 15201–15250 with only 2 engine plugin dependencies. Use Lite for safe exploration; use the full plugin for write automation.

Q: Can I register my own commands? Yes. C++ commands: RegisterShellCommand() on the shell subsystem (or derive from ULLMEasyShellAbilityCommandObject). Python commands: drop a .py into Content/Python/LLMShellAbilities/abilities/ — or host your own ability package in your plugin.

Q: Is this safe to leave running in production? No — this is an editor automation tool. The TCP server exposes full editor write capability. Disable it in shipping builds; never expose it to untrusted networks.


LLMEasyShell v1.3.0 | YominUnreal

Powered by VitePress