Files
Project-M/Docs/dots-setup-task.md
Luis Gonzalez 99d8d2d2a9 Set up DOTS + Netcode for Entities foundation
One-time stack setup per Docs/dots-setup-task.md (Unity 6.4.7 / 6000.4.7f1).
Packages: entities 6.4.0, entities.graphics 6.4.0, netcode 1.13.2, physics 1.4.6.

- Assets/_Project asmdef split: ProjectM.Simulation/Client/Server/Authoring (root ns ProjectM)
- GameBootstrap : ClientServerBootstrap; verified separate client + server worlds in Play Mode
- Gameplay subscene wired into SampleScene as a baking target
- Heartbeat component + Burst ISystem; EditMode smoke test green (1/1)
- In-repo Obsidian vault (Docs/Vault) incl. DR-001 (plain-Entities test over internal NetCodeTestWorld)
- Portable .mcp.json (basic-memory + serena via ${CLAUDE_PROJECT_DIR}); CLAUDE.md conventions
- .gitignore for DOTS baking cache + machine-local config

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 22:06:44 -07:00

9.1 KiB

One-Time Project Setup Task — DOTS + Netcode + Memory Stack

This is the separate setup task referenced by the /dots-dev skill. Run it ONCE per project (some steps once per machine — see §0). It installs the DOTS stack, scaffolds the project + vault, wires the memory MCPs, and writes CLAUDE.md. After this completes, /dots-dev drives feature work; this file is no longer needed (keep it for reference / the second machine).

How to run: open a normal Claude Code session in this project (NOT a worktree — the open Unity Editor + UnityMCP target the live working copy) and say "Run the DOTS setup task in Docs/dots-setup-task.md." Work top to bottom; each step has a verification.

Conventions reference: the ECS rules and context7 library IDs live in the skill at ~/.claude/skills/dots-dev/references/dots-conventions.md and …/context7-libraries.md (Windows: %USERPROFILE%\.claude\skills\dots-dev\references\). Use context7 for any current API shape — do not trust memory for DOTS APIs.

Cross-platform rule: never write a machine-specific absolute path (/Users/..., C:\...) into any committed file. Use ${CLAUDE_PROJECT_DIR} and repo-relative paths. The vault lives in-repo so it travels via git.


§0 — Per-machine prerequisites (do on EACH machine, once)

  • Install uv / uvx (for the basic-memory and serena MCP servers). macOS: brew install uv or the official installer; Windows: the official installer / winget install astral-sh.uv.
  • Install the Obsidian app and the obsidian-cli (the obsidian-cli skill drives it). Point Obsidian at <repo>/Docs/Vault once it exists (§5).
  • Copy/sync the dots-dev skill to this machine's user skills dir (~/.claude/skills/dots-dev/ on macOS, %USERPROFILE%\.claude\skills\dots-dev\ on Windows). It is path-agnostic — same files on both.
  • Confirm Unity 6.4 opens the project and the CoplayDev Unity-MCP bridge connects (mcpforunity://editor/stateready_for_tools).

The repo-committed parts (§1–§6) are done once total; §0 is the only per-machine work.


§1 — Install the DOTS stack

Add these to Packages/manifest.json (it is NOT a .csproj/.sln — editing it is correct) or via UnityMCP manage_packages(action="add", ...). Let UPM resolve the version compatible with Unity 6.4; then pin from Packages/packages-lock.json.

  • com.unity.entities
  • com.unity.netcodeNetcode for Entities (ECS). NOT com.unity.netcode.gameobjects.
  • com.unity.physics ← Unity Physics (DOTS), if the game needs collision/triggers
  • com.unity.entities.graphics ← renders entities under URP (already on URP 17.4)

(com.unity.burst, com.unity.collections, com.unity.mathematics, com.unity.transport come transitively.)

  • read_console until clean after the domain reload. Verify: manage_packages(action="list") shows all four; packages-lock.json records the resolved versions.
  • Optional cleanup: the template's com.unity.visualscripting and TutorialInfo/Readme.asset are unused for a DOTS game — remove if you don't want them (delete the asset and its .meta together).

§2 — Project structure & asmdefs

Pick a root namespace (e.g. ProjectM) and record it in CLAUDE.md. Create a Netcode-aware assembly split under Assets/_Project/:

Assets/_Project/
  Scripts/
    Simulation/   <Root>.Simulation.asmdef   → Entities, Collections, Mathematics, Burst, Unity.Physics, Unity.NetCode
    Client/       <Root>.Client.asmdef        → Simulation, Entities, Unity.NetCode, Unity.Entities.Graphics
    Server/       <Root>.Server.asmdef        → Simulation, Entities, Unity.NetCode
    Authoring/    <Root>.Authoring.asmdef     → Simulation, Entities, Unity.NetCode
  Subscenes/
  Prefabs/
  • Shared Simulation = components + systems that run in BOTH client and server worlds. Client/Server hold world-specific systems; Authoring holds …Authoring MonoBehaviours + Baker<T>.
  • Verify against the official ECS Samples / Netcode sample layout (context7 ID /unity-technologies/entitycomponentsystemsamples) — adjust the split if the current sample differs. Confirm each asmdef compiles (read_console).
  • Never create/edit .csproj/.sln; only .asmdef.

§3 — Bootstrap & worlds

  • Add a ClientServerBootstrap subclass (confirm exact method names — CreateClientWorld/CreateServerWorld/WorldSystemFilter — via context7 …com_unity_netcode_…).
  • Create a minimal subscene so baking has a target.
  • Verify: entering Play Mode creates separate client and server Worlds (check the Entities Hierarchy / world dropdown).

§4 — Smoke test (prove it compiles AND ticks)

  • One trivial unmanaged component (struct Heartbeat : IComponentData { public int Tick; }) + one ISystem+[BurstCompile] that increments it in SimulationSystemGroup.
  • One NetCodeTestWorld EditMode test that boots in-process client+server, connects, ticks N times, and asserts the component advanced. (Get the current NetCodeTestWorld API from context7.)
  • Verify: run_tests(mode="EditMode") → green; console clean of Burst/source-gen errors.

§5 — In-repo vault

Create <repo>/Docs/Vault/ via the obsidian-cli skill (plain markdown is fine if obsidian-cli isn't set up yet):

Docs/Vault/
  00_Home/Home.md                 (Map of Content)
  01_Vision/                      (pillars, locked decisions)
  02_Game_Design/                 (systems design docs)
  06_Roadmap/{Milestones,Backlog}.md
  07_Sessions/<year>/             (session logs)
  07_Sessions/_Decisions/         (decision records, DR-001…)
  _Templates/{Session_Log,Decision_Record}_Template.md
  _Meta/{Documentation_Protocol,Tags}.md
  • Point the Obsidian app at this folder as a vault.
  • Verify: obsidian-cli can list/read a note here.

§6 — Memory MCPs (.mcp.json, committed, portable)

Create <repo>/.mcp.json (or merge into existing) using ${CLAUDE_PROJECT_DIR} so it loads unchanged on both machines:

{
  "mcpServers": {
    "basic-memory": {
      "command": "uvx",
      "args": ["basic-memory", "mcp"]
    },
    "serena": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/oraios/serena",
               "serena", "start-mcp-server",
               "--context", "ide-assistant",
               "--project", "${CLAUDE_PROJECT_DIR}"]
    }
  }
}
  • Configure basic-memory's project to point at the vault: basic-memory project add gamevault "<repo>/Docs/Vault" (and set it default), per basic-memory's current docs. Verify: a semantic recall returns a hit on a vault note.
  • Run serena onboarding; test find_symbol on the §4 smoke-test system.
    • ⚠️ Serena C# caveat: its language server is flaky on Unity (auto-installs the wrong .NET, .sln load timeouts). If find_symbol errors/stalls, record it in CLAUDE.md and fall back to Glob/Grep — or add claude-context (local LanceDB vector index over Assets/ + the vault) as the documented code-search fallback. Prefer local embeddings (FastEmbed/Ollama) to keep game code off third-party APIs.
  • Verify: .mcp.json contains no machine-specific absolute paths (only ${CLAUDE_PROJECT_DIR}), so it loads on the other machine as-is.

§7 — CLAUDE.md (repo root, committed)

Write <repo>/CLAUDE.md covering:

  • Project root namespace + the asmdef split from §2.
  • The DOTS/ECS conventions (summarize / link the skill's dots-conventions.md): ISystem+Burst default, unmanaged IComponentData, IEnableableComponent, baking, jobs+allocators, ECB for structural changes, determinism (no wall-clock in predicted sim), server-authoritative + input-only clients, [GhostField]/ghost authoring. Aspects deprecated (1.4).
  • Guardrails (still valid from classic Unity): never edit .meta independently of its asset; never read/write Library/, Temp/, obj/, Logs/, UserSettings/; never edit/commit .csproj/.sln; no edits during Play Mode.
  • "Which memory tool when": serena = C# symbols, basic-memory = design knowledge over the vault, grep = literals, context7 = current DOTS APIs, native memory = machine-local facts.
  • Cross-machine rule: durable/cross-machine truth goes in the in-repo vault or CLAUDE.md (both committed); native memory/ is machine-local and does NOT sync.

§8 — Native memory seed (machine-local)

  • Append to MEMORY.md (this machine): project uses Unity DOTS + Netcode for Entities; the chosen memory stack (vault + basic-memory + serena, claude-context fallback); that /dots-dev is the dev driver and this setup is one-time. (Repeat on the other machine, or re-derive from CLAUDE.md.)

Done-when

  • All four DOTS packages installed, console clean, smoke-test NetCodeTestWorld green.
  • Assets/_Project asmdef split compiles; client+server worlds spin up.
  • Vault scaffolded; obsidian-cli reads it; basic-memory recalls a note; serena resolves a symbol (or fallback recorded).
  • CLAUDE.md + committed .mcp.json (portable) exist.
  • Second machine reproduces from §0 alone (everything else is in git).