Every “Claude Code for Unity” guide currently online covers the same ground: install an MCP server, ask Claude to write a PlayerController, watch it generate a coroutine-based state machine. None of them mention the failure mode that actually corrupts Unity projects when an AI agent is given normal file-editing tools inside one — direct text edits to the YAML files Unity uses for scenes, prefabs, and ScriptableObjects. We checked the existing 2026 guides on this topic and found zero mentions of .meta files, scene YAML, or Unity’s Force Text serialization setting, despite this being the single most common way an AI coding agent does real damage to a Unity project that dotnet build-style compiler feedback would never catch.
This is a CLAUDE.md built around what actually breaks Unity projects when Claude Code has normal Read/Write/Edit access to the repo, plus a template for the more common case — script-only work — where none of this applies. It also covers the current Unity 6.x drift points (render pipeline deprecation, Input System, editor version naming) that a model’s training data won’t reliably know about. Browse a real Unity .cursorrules example — Unity Game Development (C#) — in our gallery.
The Failure Mode Nobody’s CLAUDE.md Guide Mentions
Unity stores four kinds of files that Claude Code can technically open and edit like any other text file, but that aren’t meant to be edited as text at all:
.unityscene files — a YAML document listing every GameObject, its components, and its position in the hierarchy, addressed internally by numeric file IDs.prefabfiles — the same YAML format, for a single reusable GameObject hierarchy.assetfiles for ScriptableObjects — YAML-serialized data assets.metafiles — one per asset, holding the GUID Unity uses to resolve every cross-reference in the project
These files reference each other by GUID and file ID, not by name or path. A prefab’s .meta file holds the GUID that every scene referencing that prefab uses to find it; a scene’s YAML holds file IDs pointing at specific components on specific GameObjects. None of this is designed to be hand-edited, and Unity’s own manual is explicit that these are internal formats intended to be written by the Editor’s serializer, not by a text editor.
An AI agent with plain file-editing tools doesn’t know any of this by default. Asked to “rename this GameObject” or “fix this prefab reference,” it’s fully capable of opening the YAML and editing it directly — technically valid-looking YAML that either breaks a GUID reference (an object that silently becomes None in the Inspector) or, worse, produces a file the Editor can no longer parse at all, which surfaces as Unity refusing to open the scene or throwing console errors on domain reload with no clear cause. Because none of this fails at compile time, it doesn’t show up until someone opens the Editor — often a different person, later, with no idea what changed.
The rule that actually prevents this: Claude Code should only ever touch Unity project data through .cs scripts (editor scripts included) or through an MCP server that calls Unity’s Editor APIs. Direct edits to *.unity, *.prefab, *.asset, and *.meta files should be blocked outright, not just discouraged in prose.
A CLAUDE.md Template for Unity Projects
# CLAUDE.md — Unity Project
## Environment
- Unity Editor version: 6000.3.2f1 (pin the exact patch — see ProjectSettings/ProjectVersion.txt)
- Render pipeline: URP (Universal Render Pipeline) — do not write Built-in RP or HDRP-only APIs
(Camera.RenderWithShader, the legacy post-processing stack, surface shaders)
- Input: New Input System package (com.unity.inputsystem) — do not use the static
Input.GetKeyDown / Input.GetAxis / Input.mousePosition API
- UI: UI Toolkit for editor tooling and new runtime UI; uGUI (Canvas/RectTransform) for
existing runtime screens — do not migrate existing uGUI screens unless asked
- Scripting backend: IL2CPP, target .NET Standard 2.1 API compatibility level
- Async: prefer coroutines for frame-timed/Editor-lifecycle work, UniTask for anything that
needs proper async/await semantics or cancellation — do not use raw Task/async void in
MonoBehaviour callbacks
## Hard rules — file types Claude Code must not edit directly
- Never edit *.unity, *.prefab, *.asset (ScriptableObject data), or *.meta files as text.
These are YAML formats with internal GUID/file-ID references that the Unity Editor's
serializer manages. A text edit that looks correct can silently break a reference or
corrupt the file in a way that only surfaces when someone opens the Editor.
- To change a scene, prefab, or ScriptableObject's data: write or modify a C# script
(a MonoBehaviour, an [ExecuteInEditMode] component, or an Editor/EditorWindow script)
that makes the change through Unity's own APIs, or make the change through an MCP
server backed by the Editor (see below) — never through a raw file write.
- If a task genuinely requires scene/prefab changes and neither a script nor MCP for
Unity is available, stop and say so rather than editing the YAML directly.
## Project structure
- Runtime scripts: Assets/Scripts/
- Editor-only scripts: Assets/Editor/ (must be wrapped or reside in an "Editor" folder
so they're excluded from player builds)
- ScriptableObject definitions: Assets/Scripts/Data/
- Assembly definitions (.asmdef): [list boundaries — e.g. Core, Gameplay, Editor, Tests]
## MonoBehaviour conventions
- Cache component references in Awake(), not in Update() or on every access
- Use [SerializeField] private fields over public fields for Inspector-exposed state
- Null-check with Unity's overloaded == (which accounts for destroyed objects), not ?.
on UnityEngine.Object-derived types — `component?.DoThing()` can throw on a destroyed
object because the overloaded null check is bypassed
- OnDestroy must unsubscribe from any event/delegate the object subscribed to in
OnEnable/Awake — Unity does not do this automatically and it's the most common source
of "why is this still running after the scene changed" bugs
## Testing
- Unity Test Framework: EditMode tests in Assets/Tests/EditMode/, PlayMode tests in
Assets/Tests/PlayMode/
- Run via: Window > General > Test Runner, or `Unity -runTests -batchmode -projectPath . -testResults results.xml`
- New gameplay logic that doesn't require MonoBehaviour lifecycle should be written as
plain C# classes and covered by EditMode tests, not PlayMode tests, for speed
## Version control
- Asset Serialization mode: Force Text (Edit > Project Settings > Editor > Asset
Serialization) — required so scene/prefab diffs are readable and mergeable at all
- Version Control mode: Visible Meta Files (Edit > Project Settings > Version Control)
- .gitignore: Library/, Temp/, Obj/, Build/, Builds/, .vs/, .idea/ — never commit Library/
- .gitattributes: mark *.unity, *.prefab, *.asset -diff (treat as binary for diff purposes
even in Force Text mode) so routine merges don't try to line-merge YAML that isn't safe to
merge that way — real conflicts still need Editor-assisted or manual resolution
Why the Serialization and Version Control Settings Matter More Here Than Elsewhere
Force Text vs. Force Binary asset serialization. Unity’s Editor Settings has an Asset Serialization mode with three options: Force Binary, Force Text, and Mixed. Force Text is Unity’s current default for new projects, and it’s the only mode where scene, prefab, and ScriptableObject files are stored as readable YAML rather than an opaque binary blob. This isn’t just a human-readability convenience — an AI agent that’s asked to review a diff, explain what changed in a scene, or reason about a merge conflict is reading the same file a human would in version control. In Force Binary mode, that file is unreadable to both the reviewer and the model. A couple of asset types (LightingData.asset, baked NavMesh.asset) stay binary regardless of this setting because of their size, which is worth noting in CLAUDE.md so nobody’s surprised when those specific diffs are unreadable even with Force Text on.
Visible Meta Files. Unity’s Version Control project setting controls whether .meta files show up in the file system at all. With Hidden Meta Files, they’re hidden from Explorer/Finder (though still invisible in the Project view either way) and Unity manages them outside your normal file listing — fine for solo work with no VCS, but it means a text-editing agent can’t see or reason about the GUID mappings it’s implicitly relying on. Visible Meta Files is the default and the only mode compatible with Git; it’s what makes the “one GUID per asset” system something an agent (or a human doing code review) can actually inspect.
MCP for Unity: The Actual Alternative to Direct File Edits
The hard rule above — no direct edits to scene/prefab/meta files — doesn’t mean Claude Code can’t touch scenes at all. MCP for Unity (the actively maintained fork of the original unity-mcp project, MIT-licensed, sponsored by Aura) runs a local server that exposes 47 tool entrypoints for creating and modifying GameObjects, editing C# scripts, managing assets, running tests, profiling, and building — all through the Unity Editor’s own runtime APIs, not through raw YAML edits. It supports Unity 2021.3 LTS through 6.x, requires Python 3.10+ via uv, and installs through the Package Manager (Window > Package Manager > Add package from git URL with https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main) or OpenUPM. It works with Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Cline, and Gemini CLI — configuration for all detected clients is one menu command (Window > MCP for Unity > Configure All Detected Clients) after install.
The practical distinction to put in CLAUDE.md: MCP for Unity’s tools go through UnityEditor.PrefabUtility, EditorSceneManager, and equivalent APIs internally, which means the Editor itself validates every change and regenerates GUIDs/file-IDs correctly. A text edit to the same .prefab file bypasses all of that validation. If a project has MCP for Unity configured, tell Claude Code to use it for anything touching scenes or prefabs and to fall back to C# scripts for everything else — never to fall back to a raw file edit because the MCP tool “isn’t available for this specific case.”
For projects that don’t want the MCP server at all — smaller solo projects, or teams that don’t want an always-on local bridge process — script-only is a completely valid choice. Every scene/prefab change just has to go through a script (an Editor script calling PrefabUtility.SaveAsPrefabAsset, for instance) instead of a direct file write. The CLAUDE.md rule is the same either way: script or MCP tool call, never a raw edit to the underlying file.
Version and Pipeline Drift: What a Model Gets Wrong by Default
Three things changed in Unity recently enough that a model’s training data skews toward the old behavior unless CLAUDE.md says otherwise:
Unity 6 isn’t “Unity 2026,” and the naming itself is a trap. What would have shipped as “2023 LTS” under Unity’s old year-based naming was instead renamed Unity 6, with a version format of 6000.x.y (for example 6000.3.2f1). This wasn’t a version bump so much as a rebrand — Unity moved away from calendar-year names specifically because the LTS release often shipped in a different year than its name implied. If CLAUDE.md just says “Unity 6,” that still spans multiple yearly LTS lines (6000.0 through the current 6000.3+ line) with real API differences between them; pin the exact editor version string from ProjectSettings/ProjectVersion.txt, not the marketing name.
The Built-in Render Pipeline is now the pipeline you shouldn’t start new projects on. Unity began formally deprecating the Built-in Render Pipeline starting in the Unity 6.5 cycle. It keeps working — existing projects on Built-in RP remain supported for years — but Unity is explicit that new projects should be on URP going forward. A model asked to write shader or post-processing code without being told which pipeline is in use will often default to older Built-in RP patterns (surface shaders, Camera.RenderWithShader, the legacy post-processing stack) simply because that’s what dominates older tutorials and Stack Overflow answers. State the pipeline explicitly, and if the project is one of the (shrinking, but real) codebases still on Built-in RP intentionally, say that explicitly too — don’t let the model “helpfully” start writing URP shader code into a Built-in RP project.
The legacy Input Manager is on its way out, and most existing code still uses it. Unity’s manual states plainly that the legacy Input Manager — the static Input.GetKeyDown() / Input.GetAxis() / Input.mousePosition API most Unity tutorials still teach — is less flexible than the Input System package and will be removed in a future Unity version, and that projects should use the Input System package unless they’re maintaining old code written against the legacy one. Because so much of the training data a model has seen uses the old static API, this is exactly the kind of default a CLAUDE.md needs to override explicitly, not assume the model will infer from context.
Two Templates, Not One
Most Unity projects don’t need the MCP setup or the full hard-rules section above — plenty of Unity work with Claude Code is pure gameplay-script iteration that never touches a scene file. The template in this article is deliberately layered so a script-only project can drop the “MCP for Unity” and most of the “Hard rules” section and keep everything else (version pins, MonoBehaviour conventions, testing, version control settings) — those apply regardless of whether scene editing is in scope. Add the hard rules back in the moment a task starts asking for GameObjects to be placed or prefab references to be wired up, because that’s exactly the point where a text-editing agent starts reaching for the YAML directly.
For more on structuring rules files by what a project actually needs rather than a generic template, see our guide on AI coding rules by use case, and for the general C#/.NET conventions this article doesn’t repeat (naming, DI patterns outside Unity’s own component model, testing conventions for non-MonoBehaviour code), see Claude Code for .NET and C#.