unity-plugin
DeepSeek Harness plugin: control the Unity Editor through the unity CLI
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 28, 2026
- Updated
- Aug 28, 2026
Introduction
English | 中文
unity-plugin
A DeepSeek Harness plugin that lets the agent build Unity games by driving the Unity Editor through the official unity CLI: project creation, live-Editor scene commands, in-Editor C# eval, tests, and builds.
What it registers
| Tool | Purpose |
|---|---|
unity_status | Report running Editor instances reachable via the Pipeline server. |
unity_list_commands | Discover the connected Editor's command catalog with parameter schemas. |
unity_command | Run one live-Editor command (create_gameobject, get_scene_hierarchy, save_scene, …); completes in under a second with no domain reload. |
unity_eval | Execute C# inside the Editor process with full UnityEngine/UnityEditor access. |
unity_cli | Raw escape hatch for every other CLI surface: projects create, open, pipeline install, templates list, editors, test, build, auth, license, logs. |
When the dsh deployment has skill support (a composed skills service; the standard profiles do), the plugin mounts two skill roots through @deepseek-ai/dsh-skill-filesystem:
- Unity's official skill collection, fetched at plugin activation from Unity-Technologies/skills (unity-cli, new-unity-project, build-live-game, the ui family, package management, physics, optimization, multiplayer, and more) into
<dshHome>/cache/unity-plugin/unity-skills. The fetch is a shallow git clone of the configuredunitySkillsRef(default: a pinned known-good commit; set a branch such asmainto snapshot newer content). Content is fetched once per configured ref; changing the ref re-fetches. If the fetch fails, an existing cache keeps serving; with no cache the plugin logs a warning and runs with only its own skills. Mechanism and upstream-defect handling: assets/UNITY-SKILLS-UPSTREAM.md. - The plugin's own skills (
assets/skills/):unity-workflow, theunity_*tool operating knowledge (status-first discipline, project bootstrap sequence, scene loop, build/test invocations), andunity-asset-store, search/download/install of the user's owned Asset Store purchases.
All mounted skills use the standard bundled rank, so a same-named project- or user-level skill overrides them.
When the deployment has user-settings support (a composed settings service; the standard profiles do), the plugin also registers the unity settings namespace (the user-editable subset: both timeouts and the output cap), and its browser half adds a Unity CLI card to the dsh web GUI under Settings → Plugins → Plugin configuration. Values saved there override the composition config per user, mark themselves as overridden, and apply live: the tools and warm shell remount with the new values without a restart. Empty fields inherit the deployment configuration.
Live-Editor tools return the CLI's uniform JSON envelope ({ success, command, data, errors, warnings }) as structured output, so they compose cleanly with Code Mode.
Prerequisites
- The
unityCLI installed and authenticated (unity auth status), with an activated license. - A Unity 6.0+ Editor for live control; the target project needs the
com.unity.pipelinepackage (unity pipeline install --project-path <p>; the agent can run this itself viaunity_cli).
Install
Into a dsh profile (dsh plugin add passes the spec to pnpm add, so any spec pnpm accepts works):
dsh plugin --profile <name> add @opdsh/unity-plugin # from npm
dsh plugin --profile <name> add github:opdsh/unity-plugin # from GitHub
dsh plugin --profile <name> add /path/to/unity-plugin # local checkout
dsh --profile <name> --dump-config # verify the "# == unity-plugin" layer
dsh --profile <name>
Installing from GitHub (rather than npm) builds the package through its prepare script, which pnpm blocks until the package is allowlisted. The first attempt fails with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED; add this to the profile's pnpm-workspace.yaml and re-run:
onlyBuiltDependencies:
- "@opdsh/unity-plugin"
A local checkout installs as a link and needs no allowlist entry, but you must build it yourself first (pnpm install && pnpm build).
The bundle patch inserts the plugin with schema defaults. Override configuration from the profile's cordis.patch.yml (a patch replaces the row's whole config):
- insert:
- id: unity
name: '@opdsh/unity-plugin'
config:
unityBin: unity
projectPath: /abs/path/to/MyGame # default target for live-Editor tools
commandTimeoutMs: 120000
cliTimeoutMs: 600000
graceMs: 5000
outputMaxBytes: 512000
env: {} # e.g. UNITY_SERVICE_ACCOUNT_ID/SECRET for CI
warmShell: true # live-Editor tools reuse one `unity shell` process
shellIdleMs: 300000 # idle warm session disposal
unitySkillsRepo: https://github.com/Unity-Technologies/skills # '' disables the download
unitySkillsRef: 87fac23d66a1f44f5e06c2935eccce0b40b9715a # or a branch, e.g. main
Development
pnpm install
pnpm typecheck
pnpm build
The build emits two artifacts: lib/index.mjs (the Node half the dsh Loader imports) and lib/client.js (the browser half in the harness client-bundle shape, declared via dsh.client in package.json and served by the web GUI at /plugins/@opdsh/unity-plugin/client.js). The client-modules scan resolves the plugin by package name from the profile directory, so the browser half loads only when the plugin is installed into the profile (dsh plugin add); the absolute-path --patch dev overlay loads the Node half only.
To load from source against a deepseek-harness checkout without installing, write a patch overlay naming this checkout's entry point (the path must be absolute, and pnpm install must have run here first so the source imports resolve):
# dev.cordis.yml
- insert:
- id: unity
name: '/abs/path/to/unity-plugin/src/index.ts'
Then run it from the deepseek-harness checkout:
pnpm dsh web --patch /abs/path/to/dev.cordis.yml
Design notes
- Tools spawn the CLI through the harness
subprocessservice (argv, never shell-interpreted; bounded collected output; tree-scoped termination; abort signal forwarded so tool timeouts kill the process tree). - The four live-Editor tools (
unity_status,unity_list_commands,unity_command,unity_eval) run through a warmunity shell --protocol ndjsonsession (one long-lived CLI process per working directory;{"id","argv"}request lines,{"id","exitCode","envelope"}responses), cutting per-call latency from ~600 ms of CLI start to single-digit milliseconds. Requests serialize per session; a tool timeout or cancellation mid-request kills the session tree (one request in a shared process cannot be cancelled alone) and the next call respawns it; idle sessions are disposed aftershellIdleMs. SetwarmShell: falseto fall back to one CLI process per call (e.g. a CLI version withoutunity shell).unity_clialways spawns per call: builds and tests run long and want raw streams, not a serialized REPL turn. - Every invocation runs with
--non-interactiveso a command needing interactive input fails loud instead of hanging the agent. - The subprocess service scrubs credential-shaped environment variables from the child; CI service-account credentials must be passed explicitly via the
envconfig field. - Alternative integration: the CLI ships an MCP stdio server (
unity mcp) exposing the same Editor commands. Connecting@deepseek-ai/dsh-mcp-clientto it (command: unity,args: [mcp]) works with zero code, but forfeits dsh render cards, config validation, and curated tool descriptions. This plugin exists to provide those.
Known limitations
- The Editor command set is discovered at runtime; this plugin does not pin or validate per-command parameter schemas.
unity_clipays one CLI process start per call by design (see Design notes); only the four live-Editor tools use the warm session.