Problem
A recurring script eval failure mode: the C# expression is correctly wrapped in single quotes for the shell, but inner double quotes get written as \" — the escaping rule for double-quoted shell strings. Inside single quotes the backslash passes through literally, so the compiler receives \" and fails:
unityctl script eval 'return $"spawn0={(SpawnPoints.Count > 0 ? SpawnPoints[0].position.ToString() : \"none\")}";'
(13,..): error CS1039: Unterminated string literal
(13,..): error CS1073: Unexpected token '\'
(13,..): error CS1056: Unexpected character '\'
The trigger is almost always the same idiom: a $"key={value} ..." status/debug string that needs a nested quoted literal (\"none\", GetFloat(\"Speed\")). Self-repair tends to stay inside the broken frame (e.g. retrying with @\"...\" — still mangled); recovery usually means falling back to writing a temp .cs file and script execute, costing a couple of round-trips per incident.
The skill currently doesn't address this: the Script Execution section shows single-quoted examples but never states the bare-quotes rule, and the eval→file escalation criterion ("for complex scripts") is too vague to fire before the failure happens.
Proposed skill changes (UnityCtl.Cli/Resources/SKILL.md, Script Execution section)
1. Prefer structured returns over interpolated strings — removes the need for nested quotes entirely, and gives structured output for free. This single pattern would prevent nearly all instances:
# Instead of: return $"scene={s.name} bots={bots.Length} target=\"{t.name}\"";
unityctl script eval 'var s = SceneManager.GetActiveScene(); return new { scene = s.name, bots = bots.Length, target = t?.name };'
2. Explicit anti-pattern callout with a wrong/right pair (examples teach better than prose):
unityctl script eval 'return t != null ? t.name : \"none\";' # WRONG — \" inside single quotes breaks compilation
unityctl script eval 'return t != null ? t.name : "none";' # RIGHT — write quotes bare
3. Crisper escalation rule: if the expression contains a string inside an interpolated string, an apostrophe, or more than ~2 statements, switch to Write-tool + script execute <file>.cs before attempting inline eval.
4. Document stdin — script eval/script execute already read from stdin when input is redirected, but it's only discoverable via an error message.
Optional tool-side companion
There's precedent for repairing shell mangling in the CLI (the MINGW ! → \! fix in ScriptCommands.cs). Same spirit here: when eval compilation fails with Unexpected character '\' and the source contains \", retry once with \" → " substituted; if that compiles, run it and append a note about the auto-fix. That converts the entire failure class into a non-event regardless of guidance.
Problem
A recurring
script evalfailure mode: the C# expression is correctly wrapped in single quotes for the shell, but inner double quotes get written as\"— the escaping rule for double-quoted shell strings. Inside single quotes the backslash passes through literally, so the compiler receives\"and fails:The trigger is almost always the same idiom: a
$"key={value} ..."status/debug string that needs a nested quoted literal (\"none\",GetFloat(\"Speed\")). Self-repair tends to stay inside the broken frame (e.g. retrying with@\"...\"— still mangled); recovery usually means falling back to writing a temp.csfile andscript execute, costing a couple of round-trips per incident.The skill currently doesn't address this: the Script Execution section shows single-quoted examples but never states the bare-quotes rule, and the eval→file escalation criterion ("for complex scripts") is too vague to fire before the failure happens.
Proposed skill changes (
UnityCtl.Cli/Resources/SKILL.md, Script Execution section)1. Prefer structured returns over interpolated strings — removes the need for nested quotes entirely, and gives structured output for free. This single pattern would prevent nearly all instances:
2. Explicit anti-pattern callout with a wrong/right pair (examples teach better than prose):
3. Crisper escalation rule: if the expression contains a string inside an interpolated string, an apostrophe, or more than ~2 statements, switch to Write-tool +
script execute <file>.csbefore attempting inline eval.4. Document stdin —
script eval/script executealready read from stdin when input is redirected, but it's only discoverable via an error message.Optional tool-side companion
There's precedent for repairing shell mangling in the CLI (the MINGW
!→\!fix inScriptCommands.cs). Same spirit here: when eval compilation fails withUnexpected character '\'and the source contains\", retry once with\"→"substituted; if that compiles, run it and append a note about the auto-fix. That converts the entire failure class into a non-event regardless of guidance.