CLAUDE.md documents repository layout, the Unity command line, the dialogue content pipeline, validation, conventions, and known traps. AGENTS.md points at it for non-Claude agents. docs/restructure-plan.md covers both halves of the restructure: moving character and voice prose out of JSON string fields into a writer-facing writing/ tree, and migrating off the single-scene DialogueTest scaffold into Bootstrap/Systems/Level scenes. Phase 0 is recorded as executed; everything from Phase 1 on is proposal. Two findings in it were corrected after first being got wrong: the Unity CLI is installed (just not on PATH for non-interactive shells) and does have build and test commands, and the binary scene is not a stale save but a standing Unity behaviour where Force Text converts only when the setting changes. Co-Authored-By: Claude Opus 5 <[email protected]>
30 KiB
Restructure Plan — writer-facing content pipeline + migration off the test scaffold
Status: proposal, not executed. Nothing in this document has been applied to the
repository. Two files were written as part of producing it — CLAUDE.md and AGENTS.md
at the repo root — because they were requested as deliverables. No asset, script, scene
or setting was moved, renamed or altered.
Companion reading: docs/skill-system-refactor-plan.md, docs/candidate-system-plan.md,
docs/candidate-system-implementation-plan.md.
0. Status — Phase 0 is complete
Executed 2026-08-25. The working tree is clean and tagged pre-restructure.
All previously uncommitted work is now in git across five commits: camera/locomotion/interaction,
the UI layer, player control setup, the dialogue-vs-menu interaction fix, and the scene itself.
A full pre-flight backup was taken first (.tar.gz of the tree excluding Library/, Temp/,
Logs/, and build output) plus a separate copy of the scene file.
Everything below from §1 onward is unchanged proposal. Nothing in §2–§5 has been applied.
0.1 The binary scene — diagnosis corrected
The original reading of this was wrong, and the correction matters for Phase 3.
The theory was that the scene had been saved during a temporary Force Binary session and merely
needed re-saving. It isn't that. Unity re-writes this scene as binary even now, with the
project set to Force Text and EditorSettings.serializationMode reporting ForceText from the
API. Force Text governs conversion at the moment the setting changes, not on every
subsequent save — so a file that entered the project as binary stays binary indefinitely.
Four approaches were tried headlessly, all failing silently with success return codes:
| Approach | Result |
|---|---|
AssetDatabase.ForceReserializeAssets(scenePath) |
Opens and imports the scene; does not rewrite scene files at all |
OpenScene + MarkSceneDirty + SaveScene(samePath) |
Returns true, writes nothing — MarkSceneDirty does not take in batch mode |
OpenScene + SaveScene(newPath) |
Writes a fresh file that is also binary, byte-identical in size |
serializationMode = Mixed → ForceText |
Mode changes as logged; no reserialize pass occurs |
The remaining fix is Editor-UI only and takes about thirty seconds:
Project Settings ▸ Editor ▸ Asset Serialization → set Mixed, let it apply, then set Force Text again. Changing the value in the dialog is what triggers the reserialize pass.
Then verify from the terminal — you want %YAML 1.1:
head -c 20 NightclubArcadia/Assets/Scenes/DialogueTest.unity
Worth knowing: this will reserialize every asset the setting touches, so expect a wide diff. That is now safe to inspect and revert per-file, because everything is committed.
The scene itself is healthy — it opens with 14 roots (Room_101, Dialogue System,
Skill System, the three UI canvases, CinemachineBrain, CinemachineCamera, Navigation,
CameraAnchor, CM_Reveal_Room101, RevealVolume_Room101, Directional Light, UI System).
Its md5 was verified unchanged across every failed attempt. The cost of it staying binary is
that it is not diffable and not mergeable — which is an argument for bringing Phase 3's
scene split forward, since the split rebuilds these files anyway.
0.2 The Unity CLI — finding corrected
The initial survey reported the standalone unity CLI as not installed and lacking build/test
commands. It is installed, at /Users/lennart/.unity/bin/unity (v1.0.0-beta.6), and it has
both build and test, plus run, open, and editor management. The original check failed
because the binary is not on PATH for non-interactive shells — unity doctor flags this
itself as check.binary-on-path warn.
It is the better tool for CI work than raw -batchmode: unity test handles NUnit and
JUnit reports, --retries with flaky detection, --rerun-failed, and --shard N/M. See
CLAUDE.md §3 for the full command set and the gotchas (unity run reserves -batchmode,
-nographics, -quit and -logFile; its output goes to Logs/Editor.log, not stdout).
1. What the survey actually found
The brief described a proof-of-concept where dialogue is authored inside the Editor. That is not what is in the repository. The state is considerably more advanced, and that changes what the work is.
1.1 Already correct — do not "fix" these
| Thing | State |
|---|---|
| Dialogue is already plain text | 679 lines across 9 .yarn files under Assets/Dialogue/{Scenes,Characters,Objects}/. No Editor authoring anywhere. |
The .yarnproject glob |
**/*.yarn. A new scene or character file is picked up with zero registration. Nothing to build here. |
| A JSON → ScriptableObject codegen pipeline exists | skill_bible.json and candidates.json are the source of truth; Assets/Editor/SkillSystemSetup.cs and CandidateSystemSetup.cs regenerate the .asset files. This is exactly the right pattern and it is already load-bearing. |
| A headless Yarn validator exists | tools/YarnCheck compiles and plays Yarn against the game's own Yarn Spinner DLLs, no Unity needed. |
| A real EditMode suite exists | ~870 LOC / 7 files, including CandidateYarnLintTests, which lints Yarn source against the candidate registry. |
| Variable discipline exists | Common.yarn declares everything project-wide so typos are compile errors. |
1.2 The real gap for a Cowork writer
It is not the .yarn files. It is three things:
-
The writing handbook does not exist as a file.
SC101.yarncites a "cap introductions at three voices" rule anddocs/candidate-system-implementation-plan.mdsays outright that the handbook is not in this repo. So the rules a writer must follow are partly in someone's head, partly scattered across code comments. A Cowork session cannot read a handbook that isn't checked in — which is precisely the "re-explaining the world each time" problem. -
The best character material is trapped inside JSON string fields.
skill_bible.jsonholds, per skill, anotesfield containing an entire embedded prose sheet — domain, what it wants for you, what it's wrong about, register, verbal tics, SUCCESS/FAILURE/PASSIVE voice samples, firing frequency, forbidden domains. It is excellent writing. It is stored as a single\n-escaped string in a machine file. A writer cannot comfortably read or revise it, and every edit risks breaking the JSON. -
NPC characters have no sheets at all. The Bartender, Bradford Kane and Chevalier Cassian Thal exist only as their
.yarnlines. There is no record of who they are, what they know, or how they speak.
1.3 Scaffold vs. load-bearing
| Verdict | Items |
|---|---|
| Load-bearing | Scripts/Skills/** (25 files, asmdef'd), Scripts/UI/** (13 files, ~1660 LOC), Scripts/Camera/** (7 files, ~727 LOC), Scripts/Player/** (5 files, ~654 LOC + Locomotion.Math asmdef), Scripts/Interaction/**, Scripts/Dialogue/**, Assets/Dialogue/**, Assets/Skills/**, Assets/Candidates/**, Assets/Prefabs/UI/**, Assets/Tests/**, tools/YarnCheck |
| Scaffold — replace | NPCStandIn.cs (global namespace, sphere-primitive placeholder, hardwired [F] prompt, "drop this on a sphere" in its own docstring), Assets/Editor/YarnDemoSetup.cs (targets DialogueTest.unity by literal path), Assets/Scenes/DialogueTest.unity itself |
| Scaffold — keep for now | Assets/Editor/UILayerSetup.cs (818 lines), PlayerControlSetup.cs (316), UILayerSetupAutoRun.cs. These are one-shot scene/prefab builders. They are how the scene got wired and they still work; retiring them is a later step, not this one. |
| Template leftovers — delete | Assets/Scenes/SampleScene.unity, Assets/Readme.asset, Assets/TutorialInfo/ |
| Should not be committed | tools/YarnCheck/bin/, tools/YarnCheck/obj/, .DS_Store files |
1.4 Infrastructure gaps
- No
.gitattributes. No Unity YAML merge driver, no LFS rule forAssets/Art/. Scene and prefab merges will conflict destructively the first time work happens on two branches. - asmdef coverage is partial. Only
SkillsandLocomotion.Math. Camera, Player, UI, Dialogue, NPCs and Interaction all land inAssembly-CSharp, so every C# edit recompiles everything. - No PlayMode tests.
Assets/Tests/is EditMode only. - No build entry point. No
-executeMethodbuild script;EditorBuildSettingslistsSampleSceneandDialogueTest. - Single branch, no remote work in flight.
mainonly,origin/mainin sync.
2. Part 1 — externalizing dialogue and character writing
2.1 The principle
Prose lives in markdown. Machine-readable structure lives in JSON. Playable content lives in
.yarn. Nothing that a writer needs to read is stored as an escaped string inside a data file.
The existing JSON-is-source-of-truth pattern is kept and extended — not replaced. What changes is that the prose half moves out of the JSON into markdown with frontmatter, and the JSON keeps only the fields code actually reads.
2.2 Proposed structure
A new top-level writing/ directory at the repo root, deliberately outside Assets/:
writing/ ← the Cowork working directory
├── README.md # "start here" for a writing session
├── STYLE.md # the missing writing handbook, finally checked in
├── GLOSSARY.md # world terms, factions, place names, in-fiction jargon
├── YARN-PRIMER.md # the ~1 page of Yarn syntax a writer needs
├── characters/
│ ├── _TEMPLATE.md
│ ├── bartender.md
│ ├── bradford-kane.md
│ └── chevalier-cassian-thal.md
├── voices/ # the eleven skills, as readable sheets
│ ├── _TEMPLATE.md
│ ├── provenance.md
│ ├── confluence.md
│ └── … (facework, the-float, room-tone, amnesty, house-pour,
│ long-shift, placement, standing-order, undisclosed)
├── scenes/
│ ├── _TEMPLATE.md
│ ├── sc101-the-card-at-the-desk.md # brief, beats, tone — NOT the dialogue
│ └── sc102-….md
└── lore/
├── candidates.md # the three readings, in prose
└── world.md # the club, the conference, the night
Playable dialogue stays exactly where it is, in NightclubArcadia/Assets/Dialogue/. Do not
move the .yarn files. They are already correct, Unity's importer watches that path, and the
.meta files there carry GUIDs that scene references depend on.
So the writer's day looks like: read writing/, write .yarn. Two directories, no Unity.
Why root and not Assets/writing/: anything under Assets/ gets a .meta file, gets
imported, and shows up in the Unity project window. Markdown notes should not be Unity assets.
Root-level also means a Cowork session can be pointed at writing/ alone.
2.3 File format: markdown + YAML frontmatter
Frontmatter carries the few fields a script may want to check; the body is unconstrained prose.
writing/characters/_TEMPLATE.md:
---
id: bartender # matches the Yarn speaker name, lowercased/kebabed
name: The Bartender # exact string used as the Yarn speaker prefix
yarn_file: Assets/Dialogue/Characters/Bartender.yarn
status: authored # planned | drafted | authored
scenes: [SC101]
knows: [doss, the-estate-drink]
---
## Who they are
One paragraph. What they want tonight.
## How they speak
Register, sentence length, contractions, what they never say.
## What they know
Bullet list. For each: does the player learn it, under what condition, and which
`$flag` records it.
## What they must never do
The negative constraints. Usually more useful than the positive ones.
## Sample lines
Three to five. Not for shipping — for calibration.
writing/voices/_TEMPLATE.md mirrors the structure already present in
skill_bible.json's notes field, promoted to real headings — domain, what it wants for
you, what it's wrong about, how it addresses you, register, verbal tics, what it never
does, opposed/allied, SUCCESS / FAILURE / PASSIVE voice, firing frequency, forbidden domains.
That structure was already good; it just needs to be readable.
writing/scenes/_TEMPLATE.md carries the brief and the beat list, plus the constraints that
are currently buried in .yarn header comments — the evidence-balance rule, the beat order, the
passive-pattern rule, any deliberate exception. SC101.yarn's 25-line header comment is the
model; it should live here and be referenced from the .yarn file, not duplicated.
2.4 Migrating the Skill Bible without losing the JSON pipeline
skill_bible.json currently holds both machine fields (axis, opposedTo, alliedWith,
targetFiringsPerHour, accentColor, startingRank, primaryChannel, clueYield) and the
prose blob (notes, plus a duplicated domain).
Proposed split, once:
- Write a one-shot script that reads
skill_bible.jsonand emitswriting/voices/<id>.md— frontmatter from the machine fields, body from the parsednotes. SkillDefinition.notesstays in the C# type and keeps rendering wherever it renders. The generator that produces it now reads the markdown body instead of the JSON string.skill_bible.jsonremains the machine source. Either it keeps anotesfield regenerated from the markdown, orSkillSystemSetup.cslearns to readwriting/voices/*.mddirectly.
Recommendation: the first. writing/voices/*.md is the human source; a small script folds
prose back into skill_bible.json; SkillSystemSetup.cs is untouched. That keeps the existing,
tested Editor pipeline unchanged and confines the new machinery to one script — which matters
because SkillRosterTests asserts against the generated assets.
The direction of truth must be written down and never ambiguous:
writing/voices/*.md ──(sync script)──▶ skill_bible.json ──(SkillSystemSetup)──▶ *.asset
human writes here machine mirror build output
An EditMode test should assert the mirror is in sync, so a JSON hand-edit fails CI instead of silently winning.
2.5 The flow back into Unity
| Change | What the writer does | Sync step | Verify |
|---|---|---|---|
| New/edited dialogue line, branch, node | edit .yarn, save |
none — importer picks it up | dotnet run YarnCheck |
New scene or character .yarn file |
create file under Assets/Dialogue/ |
none — **/*.yarn glob |
YarnCheck |
| New variable | add <<declare>> to Common.yarn |
none | YarnCheck |
| Voice prose | edit writing/voices/*.md |
run sync script → JSON | EditMode tests |
| Character sheet, scene brief, lore, style | edit writing/*.md |
none — docs only | — |
| Candidate/clue status, new clue id | edit candidates.json |
Editor menu or script reload | CandidateYarnLintTests |
The everyday writing loop has no manual sync step at all. That is the design goal and it is
already met for .yarn; the work is to reach the same property for character and voice material.
2.6 Validation a writer can run alone
cd tools/YarnCheck
dotnet run -- ../../NightclubArcadia/Assets/Dialogue # does it compile?
dotnet run -- ../../NightclubArcadia/Assets/Dialogue Bartender_Talk 2 2 0 0 # does it play?
Requires only the .NET 9 SDK — no Unity, no license, no Editor lock. This should be the first
thing writing/README.md tells a new session to run, and the last thing it tells them to run
before handing work back.
Caveat that must be stated plainly in the README, because it will otherwise cause confusion:
YarnCheck stubs <<check>>, so $check_result is always false and every check-gated branch
shows its failure side. A writer seeing only failure prose has not found a bug.
2.7 Scope boundary
Writer-owned: writing/**, Assets/Dialogue/**/*.yarn, prose fields in the two JSON files.
Code-owned: all C#, all .asset / .prefab / .unity / .meta, all ProjectSettings/,
and the implementation of any Yarn command or function.
A writer needing a new Yarn command is a request to engineering, not a task they can complete — and that is the only such boundary. Everything else about writing a scene must be self-serve.
3. Part 2 — target project structure
3.1 Scenes
The current model — one scene holding everything — is what makes DialogueTest.unity both
irreplaceable and unmergeable. The target is additive scene loading, which is also the standard
answer to Unity scene merge conflicts.
Assets/Scenes/
├── Bootstrap.unity # entry point. Systems only, no geometry. First in build list.
├── Systems/
│ └── Systems.unity # DialogueRunner, UIStateController, PlayerSkills, Commentary,
│ # camera director. Loaded additively by Bootstrap, never unloaded.
├── Levels/
│ └── SC101_ConferenceHall.unity # geometry, lights, nav mesh, NPC + interactable placement
└── Dev/
└── Sandbox.unity # scratch scene, explicitly disposable
Bootstrap loads Systems then the requested level. The payoff is direct: two people (or a
person and an agent) can edit level content and systems wiring without touching the same file,
and a corrupted level scene no longer takes the systems layer with it.
DialogueTest.unity becomes Levels/SC101_ConferenceHall.unity — renamed and split, not
rebuilt. Its contents are the asset; only its scope changes.
3.2 Folders
Mostly already right. The deltas:
Assets/
├── Art/ ← exists (placeholder portrait). Add Environment/, Characters/, VFX/
├── Audio/ ← new: Music/, SFX/, VO/
├── Dialogue/ ← unchanged. Do not move.
├── Candidates/ Skills/ ← unchanged (JSON + generated assets)
├── Prefabs/
│ ├── UI/ ← exists
│ ├── Characters/ ← new: real NPC prefabs, replacing sphere stand-ins
│ ├── Interactables/ ← new: chair, door, object interactables
│ └── Systems/ ← new: Bootstrap/Systems prefabs
├── Scenes/ ← per §3.1
├── Scripts/
│ ├── Core/ ← new: bootstrap, scene loading, save/load, service locator
│ ├── Camera/ Player/ Interaction/ Dialogue/ UI/ Skills/ ← unchanged
│ └── NPCs/ ← NPCStandIn replaced by a real NPC component (§4, step 6)
├── Settings/ ← unchanged (URP)
└── Tests/
├── EditMode/ ← unchanged
└── PlayMode/ ← new
3.3 Conventions
- Scenes:
PascalCase. Levels prefixed with their scene id —SC101_ConferenceHall. - Prefabs:
PascalCase, no_Prefabsuffix. Variants suffixed_Variant. - Scripts: one public type per file, filename = type name. Namespace
NightclubArcadia.<Area>, matching the folder. No global-namespace runtime types. - Yarn nodes: the existing conventions hold and are already consistent —
<Character>_Talk,SC###_Hook_<Subject>,Commentary_<Context>_<skill_id>. - Yarn variables: the families in
CLAUDE.md§4.2. These are lint-enforced; treat them as API. - asmdefs: one per top-level
Scripts/area, namedNightclubArcadia.<Area>. .yarnfilenames may contain spaces (Bradford Kane.yarn) — the glob handles it, but every shell command touching them needs quoting. Worth normalising to kebab-case during a rename batch; low priority.
4. The migration plan
Incremental, ordered, each step independently committable and revertible. Steps 0–2 are the safety work and should happen before anything is moved.
Effort marks are rough: S ≲1h, M a half day, L a day or more.
Phase 0 — checkpoint ✅ DONE (2026-08-25)
| # | Step | Status |
|---|---|---|
| 0.1 | Close the Unity Editor | done |
| 0.2 | Full backup of the tree + separate copy of the scene | done |
| 0.3 | Commit all uncommitted work in logical slices (§5) | done — 5 commits |
| 0.4 | Convert DialogueTest.unity to text |
blocked — Editor-UI only, see §0.1 |
| 0.5 | Tag pre-restructure |
done |
| 0.6 | Push main and the tag to origin |
pending |
0.4 is the one open item and it does not block Phase 1 or 2.
Phase 1 — repo hygiene (no Unity changes)
| # | Step | Detail | Effort |
|---|---|---|---|
| 1.1 | Add .gitattributes |
Unity YAML merge driver for *.unity / *.prefab / *.asset; LFS for Assets/Art/** binaries; * text=auto eol=lf |
S |
| 1.2 | Untrack tools/YarnCheck/{bin,obj} |
git rm -r --cached, add ignore rules |
S |
| 1.3 | Remove committed .DS_Store files, confirm ignore rule |
S | |
| 1.4 | Add a Makefile or scripts/ wrapping the CLAUDE.md commands |
make test, make yarncheck, make build |
S |
.gitattributes before any restructuring is deliberate — the moment work happens on a branch,
scene merges without a merge driver will corrupt files.
Phase 2 — writing pipeline (no Unity changes, fully parallel to Phase 3+)
| # | Step | Detail | Effort |
|---|---|---|---|
| 2.1 | Create writing/ skeleton + templates |
§2.2, §2.3 | S |
| 2.2 | Write writing/STYLE.md |
The missing handbook. Recover the rules from .yarn header comments and the three docs/ plans. Highest-value single item in this plan. |
M |
| 2.3 | Extract skill_bible.json notes → writing/voices/*.md |
one-shot script, 11 files | M |
| 2.4 | Write the sync script md → JSON + an EditMode drift test | §2.4 | M |
| 2.5 | Author the three character sheets | Bartender, Bradford Kane, Chevalier Cassian Thal | M |
| 2.6 | Write writing/README.md + YARN-PRIMER.md |
The Cowork session entry point, incl. the YarnCheck caveat (§2.6) | S |
| 2.7 | Move SC101.yarn's header rules into writing/scenes/sc101-*.md |
leave a one-line pointer in the .yarn |
S |
Phase 2 touches no Unity asset at all. It can proceed while the Editor is open and while Phase 3 is in flight, and it is what unblocks Cowork. Consider doing it first.
Phase 3 — scene restructure (the risky part)
| # | Step | Detail | Effort |
|---|---|---|---|
| 3.1 | Delete template leftovers | SampleScene.unity, Readme.asset, TutorialInfo/; fix EditorBuildSettings |
S |
| 3.2 | Create Bootstrap.unity + Systems/Systems.unity |
Systems empty at first | M |
| 3.3 | Copy DialogueTest.unity → Levels/SC101_ConferenceHall.unity |
Copy, do not move. Keep the original until 3.6. | S |
| 3.4 | Move systems objects out of the level scene into Systems.unity |
dialogue runner, UI layer, skills, commentary, camera director | L |
| 3.5 | Wire additive loading in Scripts/Core/ |
Bootstrap → Systems → level | M |
| 3.6 | Verify parity, then delete DialogueTest.unity |
full playthrough of SC-101 vs. pre-migration behaviour | M |
| 3.7 | Retarget YarnDemoSetup.cs or retire it |
it hardcodes Assets/Scenes/DialogueTest.unity |
S |
Step 3.4 is where things break. Do it in small commits — one system per commit, playtest between each. Do not batch it.
Phase 4 — code structure
| # | Step | Detail | Effort |
|---|---|---|---|
| 4.1 | Add asmdefs per area | Camera, Player, Interaction, Dialogue, UI, NPCs, Core | M |
| 4.2 | Add Assets/Tests/PlayMode/ + asmdef |
first test: bootstrap loads and reaches playable state | M |
| 4.3 | Add Assets/Editor/BuildPipeline.cs |
-executeMethod entry, EditorApplication.Exit(1) on failure (CLAUDE.md §3.4) |
M |
| 4.4 | Rename batch | DialougueSkillComparison.cs → DialogueSkillComparison.cs; kebab-case .yarn filenames. Rename in the Unity Editor so .meta GUIDs are preserved. |
S |
Phase 5 — replace the scaffold
| # | Step | Detail | Effort |
|---|---|---|---|
| 5.1 | Design the real NPC component | data-driven from a character definition asset, not public fields on a sphere | M |
| 5.2 | Build Prefabs/Characters/ prefabs |
one per named character | M |
| 5.3 | Migrate scene NPCs off NPCStandIn, delete it |
proximity prompt + label logic is worth keeping — extract, don't discard | M |
| 5.4 | Retire the Assets/Editor/*Setup.cs one-shot builders |
only once prefabs are authored and committed; UILayerSetup.cs alone is 818 lines of accumulated wiring knowledge |
L |
4.6 Keep / relocate / replace, at a glance
| Verdict | Items |
|---|---|
| Keep as-is | Assets/Dialogue/**, Assets/Skills/**, Assets/Candidates/**, Scripts/Skills/**, Scripts/UI/**, Scripts/Camera/**, Scripts/Player/**, Scripts/Interaction/**, Scripts/Dialogue/**, Assets/Tests/EditMode/**, Assets/Prefabs/UI/**, tools/YarnCheck, Assets/Settings/** |
| Rename / relocate | DialogueTest.unity → Levels/SC101_ConferenceHall.unity (+ split); skill_bible.json prose → writing/voices/*.md; SC101.yarn header rules → writing/scenes/; DialougueSkillComparison.cs spelling; .yarn filenames with spaces |
| Replace | NPCStandIn.cs → real NPC component + prefabs; YarnDemoSetup.cs → retargeted or retired; single-scene model → Bootstrap/Systems/Level |
| Delete | SampleScene.unity, Readme.asset, TutorialInfo/, committed bin/ obj/ .DS_Store |
| Add | .gitattributes, writing/**, Scripts/Core/**, Tests/PlayMode/**, Editor/BuildPipeline.cs, per-area asmdefs, Assets/Audio/ |
5. Checkpointing — what was done
Roughly 3,100 lines of C# across untracked directories, 291 changed lines in tracked scripts, 5 UI prefabs and the scene were uncommitted. All of it is now in git.
Order used, which differs from the original draft on one point: the safe text work was
committed before any Unity run, so that a headless Editor invocation could not endanger it.
That turned out to matter — four Unity runs followed, one ending in a SIGILL on teardown.
- Verified the Editor was closed and no lockfile was held.
- Took a full backup: a
.tar.gzof the tree excludingLibrary/,Temp/,Logs/and build output, plus a separate copy of the scene file. - Committed in five slices, in dependency order:
| Commit | Contents |
|---|---|
add camera rig, click-to-move locomotion, and click interaction |
Scripts/{Camera,Player,Interaction}, locomotion math tests, Cinemachine package, Interactable/Ground tags, NavMesh agent dimensions |
add UI layer: dialogue stream, HUD, player menu, and skills panel |
Scripts/UI, Skills UI views + asmdef reference, Prefabs/UI, placeholder art, UILayerSetup |
wire player control setup and tune the third-person controller |
PlayerControlSetup.cs, StarterAssets input/armature/controller |
suppress world interaction while a menu panel is open |
Scripts/Dialogue, Scripts/NPCs, yarnproject graph positions |
check in the DialogueTest scene and add it to the build settings |
the scene (binary, deliberately) + EditorBuildSettings |
- Attempted the binary→text conversion four ways; all failed (§0.1). Committed the scene as binary rather than leave it untracked — a valid, intact, opening scene in an awkward format beats days of wiring living only on disk.
- Tagged
pre-restructure.
Slices rather than one lump, because the restructure will want to revert part of this later.
Still to do: push main and the tag to origin, and the Editor-UI serialization fix (§0.1).
5.1 Residual risks after checkpointing
| Risk | Mitigation |
|---|---|
| Scene re-save produces a text file that differs semantically from the binary one | Play SC-101 end to end before committing; compare against the pre-migration run |
Renaming assets outside Unity orphans .meta GUIDs |
Rename inside the Editor, always |
| Scene merge conflicts once branching starts | .gitattributes merge driver in Phase 1.1, before any branch |
Deleting UILayerSetup.cs too early loses wiring knowledge |
Phase 5.4 is last, and only after prefabs are authored and committed |
| Binary scene state recurs | Verify EditorSettings shows Force Text; add a CI check that *.unity files start with %YAML |
6. Sequencing recommendation
Phase 0 today. It is under an hour and it is the difference between a recoverable project and a lost week.
Then Phase 2, before Phase 3. The writing pipeline touches no Unity asset, cannot break the
game, and is what actually unblocks the stated goal of writing with Cowork. Phase 3 is the risky
work and it does not need to come first. writing/STYLE.md (2.2) is the single highest-value
item in this document — it is the artifact whose absence is currently forcing you to re-explain
the world every session.
Phase 1 alongside Phase 2, since .gitattributes must land before any branching.
Phase 3–5 after, in order, small commits, playtest between each.
7. Open questions
- Does a writing handbook exist outside the repo?
docs/candidate-system-implementation-plan.mdsays it exists but is not checked in. If there is a document somewhere, importing it beats reconstructing it (Phase 2.2 assumes reconstruction). How did the scene become binary?Answered (§0.1): Force Text only converts when the setting changes, so anything that entered binary stays binary. The open part is how it first entered binary — most likely created or imported during a Force Binary window. Adding a CI check that every*.unitystarts with%YAMLwould catch a recurrence cheaply.- Is
SC101_ConferenceHallthe right level granularity, or should the conference hall split further (entrance / hall / bar / back office) given the$visited_*flag families already declared inCommon.yarn? Those flags imply at least seven distinct locations. - Target platform(s)?
EditorBuildSettingsand the URP settings carry both PC and Mobile render pipeline assets. It affects whether Phase 4.3's build script targets one platform or several. - Should
writing/be a separate repository so Cowork sessions never see Unity? Recommendation: no — the coupling to.yarnfiles andcandidates.jsonis tight enough that split repos would drift. A single repo with a clear directory boundary is the better trade.