A system for executing AI-generated C# scripts in an open Unity Editor via Claude Cowork. Cowork writes the scripts, Bridge compiles and runs them inside Unity, then returns results and errors. On compilation errors, Cowork automatically fixes the code and retries.
The system consists of two parts:
Cowork Bridge — a C# package inside Unity Editor. It watches the Assets/Editor/CoworkBridge/ folder, picks up task files, compiles scripts, executes them via reflection, and writes results. On load it also installs a small wait-for-result.sh helper into that folder (if missing), which Cowork uses to wait for results.
Unity Bridge Plugin — a plugin for Claude Cowork. It ships two skills:
unity-bridge— instructions for Claude on script generation, the Bridge communication protocol, and error handling. It commands the Unity-side Bridge and auto-triggers on any Unity Editor task ("list all prefabs using shader X", "rename these assets"), or invoke it explicitly via/unity-bridge.unity-ui— declarative uGUI layout: creating/editing UI prefabs, dumping layout geometry, and screenshotting screens throughTask_*.ui.jsontasks (no C# compilation, no domain reload — iterations take seconds). Auto-triggers on layout phrasing ("build this popup", "move/recolor this element", "screenshot the screen"), or/unity-ui. uGUI + TMP only; UI Toolkit is not supported. See Declarative UI Tasks.
There are two task types, both dropped into Assets/Editor/CoworkBridge/ and processed sequentially in creation order:
- A C# task is the
.csscript itself — Bridge compiles and runs itsRun()method. - A UI task is a
Task_*.ui.jsonfile — Bridge applies it to a prefab directly, without compilation. Multiple agents or users can create tasks independently.
- Open Window → Package Manager in Unity Editor
- Click + → Add package from git URL...
- Enter:
https://github.com/elmortem/unitycoworkbridge.git?path=CoworkBridge - Add
Assets/Editor/CoworkBridge/to your project's.gitignore
- Copy the
CoworkBridge/folder into thePackages/folder of your Unity project - Add
Assets/Editor/CoworkBridge/to your project's.gitignore
The package has no dependencies on other project assemblies and will work even if the project has compilation errors.
Cowork is only available in the Claude desktop application (macOS and Windows). The web version and mobile apps do not support Cowork and plugins.
If you have Claude Code installed, you can load the plugin directly from a local folder:
claude --plugin-dir /path/to/unity-bridge-pluginFor permanent installation, create your own marketplace or use the --plugin-dir flag on each launch.
- Open Claude Desktop and go to the Cowork tab
- In the sidebar, click Customize
- Click Browse plugins → upload the
unity-bridge-plugin/folder or a.ziparchive of it
If you want to distribute the plugin within a team:
- Create a marketplace — a folder with a
.claude-plugin/marketplace.jsonfile containing a list of plugins - Add the marketplace to Claude Code:
/plugin marketplace add /path/to/marketplace - Install the plugin:
/plugin install unity-bridge@marketplace-name
unity-bridge-plugin/
├── .claude-plugin/
│ └── plugin.json ← plugin manifest
└── skills/
├── unity-bridge/
│ └── SKILL.md ← C# task instructions for Claude
└── unity-ui/
└── SKILL.md ← declarative uGUI layout instructions
After installation, just ask Claude to do something inside the Unity Editor (e.g. "list all prefabs using shader X" or "add a Rigidbody to all enemies") — the unity-bridge skill auto-triggers on such requests. You can also invoke it explicitly via /unity-bridge. If the plugin is installed correctly, Claude will start generating a script.
In Unity Editor, open Tools → Cowork Bridge → Start. Bridge will start watching the Assets/Editor/CoworkBridge/ folder.
Tools → Cowork Bridge → Stop
Just describe the task in natural language — the unity-bridge skill auto-triggers on Unity Editor requests:
add a Rigidbody component to all objects with the Enemy tag
If you want to force the skill to handle a request, invoke it explicitly:
/unity-bridge add a Rigidbody component to all objects with the Enemy tag
Claude will generate a script, send it to Bridge, wait for the result, and show the outcome. If there are compilation errors, it will automatically fix the code and retry (up to 3 times).
Bridge writes result_<id>.json and then an empty result_<id>.done marker. To wait for a task, the skill runs the helper that Bridge installs into the watched folder:
bash Assets/Editor/CoworkBridge/wait-for-result.sh <TaskName> <timeout-seconds>The helper polls for the .done marker, then prints the result JSON to stdout (or a {"status":"timeout"} JSON and exit code 1 if it times out). Bridge auto-creates this script in the watched folder on every Editor load when it is missing, so you never place it by hand.
To stop Claude Code from asking for confirmation on every wait, allow this exact command in your settings — ~/.claude/settings.json (all projects) or .claude/settings.local.json (per project):
{
"permissions": {
"allow": [
"Bash(bash Assets/Editor/CoworkBridge/wait-for-result.sh:*)"
]
}
}wait-for-result.sh is a bash script and must keep LF line endings — on Windows, CRLF breaks it. The package enforces this via .gitattributes (*.sh text eol=lf), so the file stays LF when Unity fetches the package. If you commit the watched folder in your own project instead of gitignoring it, add the same .gitattributes rule there too.
You can create a script manually and run it via Tools → Cowork Bridge → Run Task... (a file dialog for selecting a .cs file).
The script must follow this template:
using System.Threading.Tasks;
using UnityEngine;
using UnityEditor;
public static class Task_20260226_143052
{
public static async Task<string> Run()
{
// your code
return "result description";
}
}Run() must return Task<string> — the old string Run() signature is rejected with runtime_error. Bridge invokes Run() without blocking the editor thread and writes the result only after the returned Task completes, so you can freely await async APIs (thread pool, Task.Delay, Unity async operations). Declare the method async Task<string> even when you don't await anything (the CS1998 warning does not break compilation).
Bridge cleans up successful tasks on its own:
- Auto-trim — while idle, Bridge keeps only the last N successful tasks (default 10), removing older ones together with all their outputs (
result_*,testresult_*, and the task-ownedArtifacts/<id>/directory). N is configurable viaKeepCompletedCountinProjectSettings/CoworkBridge.json. - Orphan sweep — while idle and during any manual clean, Bridge also removes result files and
Artifacts/<id>/directories whose owning task file (.cs/.ui.json) is already gone. This catches outputs written after their task was trimmed — notablytestresult_*, produced asynchronously after a test run — which would otherwise pile up forever. clean.command— to remove all successful tasks at once, drop an empty file atAssets/Editor/CoworkBridge/clean.command. Bridge deletes every successful task and the command file itself. Don't create it while a test run is in progress.
Failed tasks (compiler_error / runtime_error) are left untouched by auto-cleanup. Manual cleanup is still available:
- Tools → Cowork Bridge → Clean Completed — removes completed tasks (script + result + marker)
- Tools → Cowork Bridge → Clean All — removes all tasks
If the project has custom APIs (libraries, tools, builders), you can describe them for Bridge so that Claude uses them when generating scripts. Create a UNITYCOWORK.md file next to the library code.
When executing a task, the skill recursively searches for all UNITYCOWORK.md files in the project and reads them. If the described API is suitable for the task, Claude will use it instead of the standard Unity Editor API.
File format:
# API Name
Brief description: what it does and when to use it.
## When to Use
Description of tasks this API applies to.
## Namespace / Using
Which using directives to add.
## Main Classes and Methods
Public API with examples.
## Examples
Ready-made examples for typical scenarios.Detailed template with recommendations: Docs/UNITYCOWORK-template.md
No separate documentation is needed for the standard Unity Editor API — Claude knows it out of the box.
Besides C# scripts, Bridge accepts a second task type for uGUI layout: a Task_YYYYMMDD_HHMMSS.ui.json file placed in Assets/Editor/CoworkBridge/. Bridge applies it to a prefab directly, without compiling C# or reloading the domain, so layout iterations take seconds. The task id is the file name without the .ui.json suffix; results are the usual result_<id>.json + .done. Scope is uGUI + TMP only — UI Toolkit is not supported.
One task targets one prefab and runs a list of actions:
{
"prefab": "Assets/Resources/Prefabs/UI/MyScreen.prefab",
"actions": [
{ "action": "apply", "target": "Popup", "node": {
"rect": { "anchorMin": [0.5, 0.5], "anchorMax": [0.5, 0.5], "pos": [0, 0], "size": [600, 400] },
"components": [ { "type": "Image", "sprite": "Assets/Sprites/UI/PopUp.png", "imageType": "Sliced", "color": "#FF005A" } ],
"children": [
{ "name": "Title", "rect": { "anchorMin": [0, 1], "anchorMax": [1, 1], "pos": [0, -40], "size": [0, 60] },
"components": [ { "type": "Text", "text": "TITLE", "size": 42, "align": "Center" } ] }
]
} },
{ "action": "shot", "outline": ["Popup"] }
]
}apply— create/update a node by path; specified properties are set, unspecified are left alone,nullclears;childrenare synced by name (extra children are never removed).delete— remove a node by path.dump— writeArtifacts/<id>/uidump.json: the whole tree with anchors, sizes,screenRectin reference pixels, and object references of custom components.shot— render the prefab offscreen toArtifacts/<id>/shot.png(1920×1080 by default) plus a.rects.jsonwith every node's screen rect;outlinedraws colored frames for the listed paths. Optionaloutputis a PNG file name only, never a path. Absolute paths and directory segments are rejected, so every transient UI artifact remains owned by its task.
Order within a task: all apply/delete run first over the loaded prefab contents, then a single save, then dump/shot over the saved asset. If the prefab does not exist and there is an apply, it is created (root RectTransform stretched 0..1). Any error (bad JSON, missing prefab/sprite/type/path) yields runtime_error and leaves the prefab unchanged.
Before laying out UI, the unity-ui skill recursively searches the project for a UNITYCOWORK-UI.md file describing your layout conventions — reference resolution, palette, fonts, art paths, prefab paths, and custom view components. Create one so Claude uses your real colors, fonts and assets instead of guessing. Template with recommendations: Docs/UNITYCOWORK-UI-template.md.
Assets/Editor/CoworkBridge/
├── wait-for-result.sh ← result-wait helper (auto-installed by Bridge)
├── Task_XXX.cs ← generated C# scripts = tasks
├── Task_XXX.ui.json ← declarative UI tasks
├── result_<id>.json ← execution results
├── result_<id>.done ← result readiness markers
└── Artifacts/
└── <id>/ ← removed together with the owning task
├── uidump.json ← UI dump output
├── shot.png ← default UI screenshot output
└── shot.png.rects.json ← screen rects for the screenshot
- Works only in Unity Editor, not in Play Mode
- Tasks are processed sequentially — while an async task is in flight Bridge picks up neither it again nor the next task
Run()is invoked on Unity's main thread; awaited continuations resume there too, so heavy synchronous work still blocks the Editor — offload it viaawait Task.Run(...). Bridge caps a task atAsyncTimeoutSeconds(default 300, configurable inProjectSettings/CoworkBridge.json); on timeout it writesstatus: "timeout"and unblocks the queue- A running async task can be aborted via Tools → Cowork Bridge → Cancel Running Task (writes
status: "canceled"and triggers a script reload). If the domain reloads mid-flight, the task auto-restarts when its.csis still in the folder - Generated scripts must not depend on assemblies with compilation errors