DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Unreal Agentlink — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
U

dsh-unreal-agentlink

Unreal Agentlink

DSH plugin bridging the UnrealAgentLink editor protocol — pure bridge: DSH's native agent plans, this plugin only exposes UE editor capabilities

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:hackmagic/dsh-unreal-agentlink#3c34d66aeba4664442a00669d9174e2295a91307
READMECompatibilityVersions

Compatibility and provenance

Unreal Agentlink is published as dsh-unreal-agentlink and currently resolves to version 0.1.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
any
Release source
github
Registry updated
10/14/2026

Versions

0.1.0stable
10/14/2026

Related plugins

Loading related plugins…

Latest
0.1.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
any
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/16/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in integrations-communication.

Im@xmanrui/dsh-im把微信、飞书、企微、钉钉、QQ、Telegram、WhatsApp、Slack、Discord、Matrix接入DSH。 Connect Telegram, WhatsApp, Slack, Discord, Matrix, WeChat, Feishu, WeCom, DingTalk, and QQ to DSH.Free Searchdsh-free-searchFree web search for DeepSeek Harness: 24 engines (Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl/Parallel keyless; Zhihu global/site via MCP and Perplexity/SerpBase/DeepSeek/You.com/Baidu/Kimi/Aliyun/Doubao with key; OpenAI/Gemini/Claude Dafeiyudsh-dafeiyuA desktop-native BigFish companion driven by DeepSeek Harness session events.Wechat Plugindsh-wechat-pluginWeChat channel for DeepSeek Harness: lock the PC, walk away, and drive the agent from your phone. No OpenClaw and no public IP required.

README

English · 简体中文 · 繁體中文 · 日本語 · 한국어 · Deutsch · Español · Français · Русский

dsh-unreal-agentlink

A DSH plugin that puts your Unreal Editor under your agent.

Pure bridge. The agent plans; this plugin only translates.

DSH agent  ──tool calls──►  dsh-unreal-agentlink  ◄──WebSocket──  Unreal Editor
(plans, decides)            (this plugin: server, translator)   editor dials out

Requirements · Quick start · Tools · Configuration · Documentation

npm install && npm run check


Your agent can already read files and run commands. This plugin gives it the editor itself: query the level, spawn actors, edit blueprints and materials, render sequences, take screenshots it can actually see, and roll its own work back when something goes wrong.

It does not plan tasks. Planning belongs to DSH's native agent. This plugin is a translator with a safety layer — it turns agent intent into UnrealAgentLink commands and turns the editor's answers back into something an agent can act on.


Requirements

ItemRequirement
Unreal Engine5.0 – 5.8
UnrealAgentLinkthe C++ plugin itself, dropped into your project's Plugins/
Node.js^22.19.0 || >=24.0.0
DSH runtimethis plugin installed as a bundle

You do not need UEBox

The UEBox desktop app is not a dependency. It is another client from the same vendor that happens to use port 17860 too, so running both at once is a port conflict — that is the whole relationship. The evidence:

  • UnrealAgentLink.uplugin:25-34 declares exactly two dependencies, both engine-shipped: IKRig and PythonScriptPlugin. No uebox module.
  • Every entry in UnrealAgentLink.Build.cs is an engine module (UnrealEd / AssetRegistry / MovieScene / Landscape …). No uebox SDK.
  • The string uebox appears three times in the entire source, all of them // Copyright uebox.ai headers.
  • Nothing in the source calls uebox.ai. The only FHttpModule use reads the local machine's proxy settings (UAL_ProxyDiagnostics.cpp:167).

Once the plugin is in your project it runs on its own: StartupModule unconditionally calls Init("ws://127.0.0.1:17860") (Core/UnrealAgentLink.cpp:86-97), pushes project.info the moment it connects, and has no handshake, token, or authentication.

To move the port: -UALServer=ws://127.0.0.1:17861 on the editor side, and the port setting on this side.


Quick start

npm install
npm run check      # typecheck (src + tests) + 162 tests + catalog + doc reconciliation, one command

To install as a DSH bundle: package.json declares dsh.bundle.patch, and cordis.patch.yml inserts one line by published package name — {id: unreal-agentlink, name: dsh-unreal-agentlink}.

Configuration layering: a later layer replaces that row's config wholesale rather than deep-merging it. To override anything, rewrite every key you want to keep.

For the end-to-end path see the tutorial — UE-side install, first connection, common workflows, and how to read failures.


Documentation

DocumentContents
TutorialEnd-to-end: install the plugin, get it connected, common workflows, troubleshooting
Protocol referenceMessage shapes, events, the 13 status codes, serialization rules, timeout and concurrency semantics
ArchitectureThe gate chain, session isolation and rollback, error translation, verification strategy, the traps we hit
Command referenceParams / required keys / result keys / status codes for all 170 commands (generated)

All four exist in every language listed at the top of this file, under docs/<lang>/ — en (canonical, at docs/ directly), zh, zh-TW, ja, ko, de, es, fr, ru.

Only the prose is translated. Command names, parameter keys, result keys, status codes, config keys and C++ line references stay verbatim everywhere, because UE silently ignores a key it does not recognize — a translated asset_path would be a silently dead key, not a localization. tests/i18n.test.ts enforces the invariants that make this maintainable: every language has its files, every switcher bar lists every language, and every internal link and #anchor resolves. That last one matters because anchors are derived from the translated heading, so rewording a heading silently breaks every link pointing at it.


Four facts to establish first

These are not design choices. They are existing UnrealAgentLink constraints, and they determine how every operation is written.

  1. The direction is reversed. This plugin does not dial the editor — the editor dials out. Startup order does not matter: open the editor first and it retries every 5 seconds until the plugin appears.
  2. There is no authentication. No token, no header, no subprotocol. The port is the credential, so it binds loopback only by default. Do not change it to 0.0.0.0.
  3. Commands run serially on the game thread. And while a blocking command runs, the editor answers nothing — not even a progress query like sequence.render_status.
  4. There is no cancellation. query_task and cancel_task do not exist. Killing a ual_task job only stops this plugin's wait; the engine keeps going and the result still comes back.

12 tools

Surfacing 170 commands as 170 tools would spend a large slice of every request's prompt on capabilities a given task never touches. So discovering capability is two steps, not zero:

ToolPurpose
ual_statusEditor connections / breaker / rate limit / session / orphaned commands. Read this first when anything is wrong
ual_toolsList all 170 commands (22 families), filterable by family or keyword
ual_schemaThe exact key names for one command — check before calling; UE silently ignores unknown keys
ual_callRun one command, return the editor's result verbatim
ual_batchSeveral commands in one round trip (capped by maxBatchCalls; one dangerous item puts the whole batch through approval)
ual_screenshotCapture and return a real image the agent can see
ual_logsRead the local log ring (UE-side forwarding is off by default — see the tutorial)
ual_undo / ual_undo_historyPer-session rollback / inspect the undo buffer
ual_locksClaim asset locks; the editor draws an "AI is editing" badge
ual_editor_bindPin a session to one editor when several are connected
ual_taskTurn a long blocking command into a real background job so the conversation continues

Risk tiers

read 65 / write 89 / destructive 2 / dangerous 14 (the last 16 go through approval).

tools/pre-execute returns {kind:'ask'} for destructive and dangerous methods (including any dangerous item inside a ual_batch), leaving the decision to session policy. An unregistered method is denied outright and never reaches the editor.

Note that under a never policy, ask is auto-rejected — which is the correct reading of "unattended sessions must not touch the editor".


Configuration

Defaults are "alive but lazy". The full table with reasoning is in tutorial §7.

KeyDefaultMeaning
host / port127.0.0.1 / 17860Keep it on loopback: with no auth, reaching the port means driving the editor
timeoutMs180000Blocking commands raise their own floors
cacheTtlMs / cacheMaxEntries2000 / 128Per-session read cache
rateLimitRps / rateLimitQueue5 / 32Commands per second / queue cap (0 disables rate limiting)
breakerThreshold / breakerCooldownMs3 / 30000Consecutive transport failures to open / cooldown
logCapacity / logMinLevel512 / DisplayLog ring
logForwardingEnabledfalseSet true only after running ual.ForwardLogs inside the editor
rollbackOnDisposefalseOnly a LIFO suffix is exact — see the architecture doc
notifyOnEditorChangetrueInject a line into the agent when an editor connects or drops
screenshotAttachments / screenshotMaxBytestrue / 12MBImage blocks / size cap
maxBatchCalls12Per-ual_batch cap

Development

npm run build       # tsc → lib/
npm run dev         # tsc --watch
npm run check       # typecheck + tests + catalog reconciliation (run before committing)
npm test            # tests only
npm run typecheck   # src and tests typechecked separately

Source layout

src/
  index.ts                  Cordis lifecycle, approval gate, dispose-time rollback
  config.ts                 Schemastery schema (the single source of default values)
  service.ts                call() gate chain: catalog → requires → read cache → breaker → rate limit → send → ledger → translate
  protocol/{bridge,serialization,types}.ts   WS server / outbound validation / wire types
  catalog/{method-data,method-overrides,methods}.ts   170-command catalog (data extracted from C++)
  errors/translate.ts       Error classification (by class name / status code, never by message text)
  resilience/breaker.ts     Rate limiter + circuit breaker
  sessions/state.ts         Session ledger / LIFO test / lock merging / cache / log filtering
  tools/                    The 12 tools
scripts/                    Catalog extraction and reconciliation, doc generation and normalization, language set
docs/                       Tutorial / protocol / architecture / command reference, in 9 languages
tests/                      162 tests

Generated files: do not edit by hand

src/catalog/method-data.ts and docs/<lang>/command-reference.md are both generated:

node scripts/extract-methods.mjs .ua-ref/plugin/UnrealAgentLink/Source   # rebuild the catalog from C++
npm run build && node scripts/gen-docs.mjs                             # rebuild the command reference (all 9 languages)

A hand-maintained table that nobody imports is a recurring defect class in this project (REQUIRED_KEYS, EXTRA_PARAM_KEYS and UAL_CODES have all been caught by it). The countermeasure is to make each check ask the source rather than ask the table — see architecture §9.

Tests and checks

npm run check                       # typecheck (src + tests) + 162 passed + catalog + doc reconciliation
npm test                            # 162 passed
node scripts/check-catalog.mjs      # 170/170 zero drift; every requires key appears in C++; code set matches C++
node scripts/gen-docs.mjs --check   # is the command reference up to date in all 9 languages
node scripts/normalize-doc-headers.mjs --check   # are the language bars canonical in all 45 files
node scripts/normalize-doc-links.mjs --check     # do the body links resolve from where they sit
npm run docs                        # regenerate + rewrite the 45 doc headers and links

The eight test files are divided by the kind of defect they can find, each for a reason — see architecture §11.

requires is not hand-written: it is derived from the handlers' own SendError(..., 400, "Missing field: X") messages (28 sites), because a wrong required key makes the bridge reject a valid call before the engine sees it. The result lands in method-data.ts as REQUIRED_KEYS, and methods.ts's requiresOf() merges it into runtime use (the early rejection in service.call(), the REQUIRED: line in ual_schema, and error hints all go through that one function).

It deliberately narrows only, never widens: a message containing or ("Missing field: name or path") is skipped entirely, and keys harvested from a called function in the same file are dropped as branch-local — see REQUIRED_DROPPED in scripts/extract-methods.mjs, where every entry cites its C++ line number. So "no keys harvested" is the safe default, not a missed check.


Protocol essentials

UE → plugin:  { ver:"1.0", type:"req",  method, id, params }     // id is generated by the server
plugin → UE:  { ver:"1.0", type:"res",  id, code, result }        // the key is omitted when empty
UE → plugin:  { ver,       type:"evt", method, payload }
  • Failure is expressed by code alone. There is no envelope-level error field.
  • Human-readable text is in result.message (Chinese or English depending on editor culture — do not parse it); machine-readable detail is in result.details.
  • Many handlers return 200 with result.ok === false (editor.undo, blueprint.compile, pie.observe), so the plugin judges success with judge(), not by code alone. There are 55 SetStringField(TEXT("error"), ...) sites across 14 C++ files — this is the norm, not an anomaly.
  • content.import_folder / content.import_assets are fire-and-forget outbound pushes: no id, no reply expected. The plugin turns them into logs and agent notifications and does not fabricate a res — replying ok:false would only show the user a false "import failed" dialog, which is worse than silence.

Full detail (all 13 status codes, serialization rules, timeout semantics) is in the protocol reference.


License

MIT