npx claudepluginhub tykisgod/quick-questionThis skill uses the workspace's default tool permissions.
Respond in the user's preferred language (detect from their recent messages, or fall back to the language setting in CLAUDE.md).
Runs Unity Test Framework tests via CLI: detects Editor, executes EditMode/PlayMode tests, parses XML results, generates failure reports. For game logic validation, debugging, CI/CD.
Selects optimal mix of plain C#, edit mode, play mode, and smoke tests for Unity features. Use when adding tests, fixing slow/brittle suites, or catching engine regressions.
Verifies Unity code changes via refresh, compile polling, error/warning console checks, auto-correction loops, and optional EditMode/Runtime tests. Auto-triggers on .cs/.shader/asmdef edits.
Share bugs, ideas, or general feedback.
Respond in the user's preferred language (detect from their recent messages, or fall back to the language setting in CLAUDE.md).
Run Unity unit/integration tests and check for runtime errors.
This skill can ALWAYS run. It supports three execution backends (tykit HTTP → Editor trigger → Unity batch mode). When Unity Editor is not open, the scripts automatically fall back to batch mode. Never skip this skill with the assumption that tests "cannot run from CLI" — they can.
Unity Backend: This skill supports multiple backends. If the built-in
tykit_mcptools are available (unity_health,unity_console,unity_run_tests, and — new in v0.5.0 —unity_main_thread_health,unity_focus_window,unity_dismiss_dialogfor recovery), use them first. If only third-party MCP tools are available (run_testsfrom mcp-unity, ortests-runfrom Unity-MCP), use those instead of the tykit/script commands below. If no MCP tools are available, use tykit as documented here. To discover tykit commands:curl -s -X POST http://localhost:$PORT/ -d '{"command":"commands"}' -H 'Content-Type: application/json'or'{"command":"describe-commands"}'for full schemas. PORT comes fromTemp/tykit.json.For tykit command usage beyond tests (scene editing, prefab workflow, runtime reflection, recovery from hangs), see
shared/tykit-reference.md.
Arguments: $ARGUMENTS
editmode / edit: EditMode onlyplaymode / play: PlayMode only--filter "TestName": Filter by test name (semicolon-separated for multiple)--assembly "Asm.Tests": Filter by assembly (semicolon-separated for multiple)--timeout 300: Custom timeout in secondsExamples:
/qq:test → Run EditMode + PlayMode/qq:test play → PlayMode only/qq:test editmode --filter "Health" → Filter by name/qq:test --assembly "Game.PlayerSystem.Tests" → Filter by assemblyunity-test.sh) via the plugin bin/ directory on PATH. If a bare command fails with "command not found", fall back to ${CLAUDE_PLUGIN_ROOT}/bin/<command>.python3 on macOS/Linux. On Windows (Git Bash), use python instead (python3 is not available). The bin/ wrappers handle this automatically.ps -p PID -o args= is macOS/Linux only. On Windows, use wmic process where "ProcessId=$PID" get CommandLine or tasklist.source "${CLAUDE_PLUGIN_ROOT}/scripts/platform/detect.sh" && qq_get_editor_log_path to get the correct path for the current OS.If qq-project-state.py is available, read it before choosing test scope:
qq-project-state.py --pretty
Interpret the result like this:
policy_profile=core → keep the default lighterpolicy_profile=feature → normal defaultpolicy_profile=hardening → prefer the stronger defaultdefault_test_scope is the current repo's effective no-argument defaultRules:
--filter / --assembly always windefault_test_scope=editmode → run EditMode onlydefault_test_scope=all → run EditMode first, then PlayModepolicy_profileBefore using tykit, verify it's reachable and talking to the correct Unity instance. If tykit.json is missing, skip this entire step — the test scripts (Step 3) automatically fall back to batch mode when Unity Editor is not running.
TYKIT_JSON="Temp/tykit.json"
if [ ! -f "$TYKIT_JSON" ]; then
echo "tykit.json not found — skipping health check, scripts will use batch mode"
# SKIP to Step 2 — batch mode does not need tykit
fi
PORT=$("${QQ_PY:-python3}" -c "import json; print(json.load(open('$TYKIT_JSON'))['port'])")
TYKIT_PID=$("${QQ_PY:-python3}" -c "import json; print(json.load(open('$TYKIT_JSON'))['pid'])")
The most common port-stealing culprit is AssetImportWorker — it can overwrite tykit.json with its own PID, leaving the port pointing at a process that isn't running TykitServer.
# macOS; on Windows use: wmic process where "ProcessId=$TYKIT_PID" get CommandLine
PROC_ARGS=$(ps -p "$TYKIT_PID" -o args= 2>/dev/null || true)
if [ -z "$PROC_ARGS" ]; then
echo "PID $TYKIT_PID is dead — tykit.json is stale"
# STOP: delete stale tykit.json, ask user to reopen Unity
fi
IS_WORKER=$(echo "$PROC_ARGS" | grep -cE "AssetImportWorker|UnityPackageManager|UnityHelper" || true)
if [ "$IS_WORKER" -ne 0 ]; then
echo "PID $TYKIT_PID is a subprocess ($PROC_ARGS), not the main Unity Editor"
# STOP: ask user to restart Unity manually (never kill — risks Library corruption)
fi
/ping)PING=$(curl -s --connect-timeout 3 --max-time 5 "http://localhost:$PORT/ping" 2>/dev/null) || true
if [ -z "$PING" ]; then
echo "tykit on port $PORT not responding to /ping"
# STOP: ask user to check Unity window for modal dialogs
fi
compile-status)/ping responds from the listener thread without touching Unity API. A modal dialog or domain reload can block the main thread, causing POST commands to hang while /ping still works. Verify POST works:
CS=$(curl -s --connect-timeout 5 --max-time 15 -X POST "http://localhost:$PORT/" \
-d '{"command":"compile-status"}' -H 'Content-Type: application/json' 2>/dev/null) || true
if [ -z "$CS" ]; then
echo "tykit POST timed out — ping works but commands do not"
# STOP: Diagnose by priority:
# 1. Re-check PID (step 1b) — Worker is the #1 cause
# 2. Check for Unity modal dialogs blocking the main thread
# 3. Wait 30s for domain reload to finish, then retry
else
echo "tykit healthy: port=$PORT pid=$TYKIT_PID"
fi
Diagnostic table:
| Symptom | Likely cause | Action |
|---|---|---|
tykit.json missing | Unity not running or never opened this project | Skip health check — scripts fall back to batch mode |
| PID dead | Unity closed but tykit.json not cleaned up | Delete stale tykit.json, ask user to reopen |
| PID is AssetImportWorker | Worker subprocess stole the port on restart | Ask user to restart Unity manually |
| PID is UnityPackageManager/UnityHelper | Other Unity subprocess inherited the port | Ask user to restart Unity manually |
/ping timeout | Unity hung or not listening | Ask user to check Unity window |
/ping OK but POST timeout | Modal dialog / stalled domain reload / package resolve blocking main thread | Call GET /health to confirm → run recovery flow below |
When POST commands time out but /ping still works, the main thread is blocked. These endpoints run on the HTTP listener thread and bypass the queue, so they work even when POST commands don't:
# 1. Confirm main thread is blocked
curl -s --connect-timeout 3 --max-time 5 "http://localhost:$PORT/health"
# Look at mainThreadBlocked and hint fields
# 2. Try bringing Unity to foreground (Windows only) — fixes 90% of stalls
# (Unity background-throttles domain reload / package resolve when unfocused)
curl -s --connect-timeout 3 --max-time 5 "http://localhost:$PORT/focus-unity"
# 3. If that fails, try dismissing a modal dialog (Windows only)
curl -s --connect-timeout 3 --max-time 5 "http://localhost:$PORT/dismiss-dialog"
# 4. After recovery, retry your POST command
Built-in tykit_mcp equivalent: unity_main_thread_health, unity_focus_window, unity_dismiss_dialog MCP tools.
Third-party MCP users (mcp-unity / Unity-MCP): These recovery endpoints are tykit-specific and have no equivalent in third-party MCPs. If POST hangs, the only options are (a) manually clicking/closing the Unity window, (b) waiting for domain reload to finish, or (c) switching to tykit direct HTTP / built-in tykit_mcp.
Rules:
kill Unity (including Workers) — risks Library corruption and cascade failuresfind_unity from unity-common.sh or let the user specifytykit.json), stop and report — do not attempt workaroundstykit.json is missing, skip to Step 2 — test scripts handle batch mode fallback automaticallyBuilt-in
tykit_mcp: Preferunity_healthand stop if it reportsok: false.Third-party MCP backends: Skip this step entirely — their tools manage their own connection.
source "${CLAUDE_PLUGIN_ROOT}/scripts/platform/detect.sh"
EDITOR_LOG="$(qq_get_editor_log_path)"
BASELINE=$(wc -l < "$EDITOR_LOG")
if [ -n "$PORT" ]; then
curl -s --connect-timeout 5 --max-time 15 -X POST http://localhost:$PORT/ \
-d '{"command":"clear-console"}' -H 'Content-Type: application/json'
fi
Built-in
tykit_mcp: Useunity_consolewithaction: "clear"when available.Third-party MCP backends: Skip this step — neither mcp-unity nor Unity-MCP has a console-clear equivalent. Runtime error checking (Step 4) uses Editor.log directly and does not depend on console state.
Select command based on arguments:
| Argument | Command |
|---|---|
(none) + default_test_scope=all | unity-unit-test.sh |
(none) + default_test_scope=editmode | unity-test.sh editmode --timeout 180 |
editmode | unity-test.sh editmode --timeout 180 |
playmode | unity-test.sh playmode --timeout 180 |
| with filter/assembly | unity-test.sh <mode> --filter "X" --assembly "Y" --timeout Z |
default_test_scope from project stateunity-test.sh and pass all arguments throughBuilt-in
tykit_mcp: Useunity_run_testsfirst. Pass mode, filter, assembly, and timeout as tool parameters. When no mode argument is given, preserve the sequencing: run EditMode first, check the result, and only proceed to PlayMode if EditMode passes. On failure, apply the same analysis as below.Third-party MCP backends: If the built-in bridge is not available, use
run_tests(mcp-unity) ortests-run(Unity-MCP) instead of the scripts above. Pass mode, filter, assembly, and timeout as tool parameters. When no mode argument is given, preserve the sequencing: run EditMode first, check the result, and only proceed to PlayMode if EditMode passes. On failure, apply the same analysis as below.
Even if all tests pass, runtime errors may still occur. Check via Editor.log (not dependent on the console API buffer):
tail -n +$((BASELINE + 1)) "$EDITOR_LOG" | \
grep -iE "NullReferenceException|Exception:|Error\b" | \
grep -v "^UnityEngine\.\|^Cysharp\.\|^System\.Threading\.\|^ at \|CompilerError\|StackTrace" | \
sort -u
Show all errors to the user — do not filter or omit any. For each error, include a source assessment (e.g., "exception from TaskEdgeCaseTests safety test, likely expected behavior"), and let the user decide whether action is needed.
After tests complete, recommend the next step:
recommended_next is /qq:doc-drift → "All green. Next up is /qq:doc-drift before shipping."recommended_next is /qq:commit-push → "All green. Ready for /qq:commit-push."<recommended_next>."/qq:test to confirm, or proceed to /qq:doc-drift?"--auto mode: skip asking:
qq-execute-checkpoint.py pipeline-advance --project . --completed-skill "/qq:test" --next-skill "<recommended_next>" (use the actual recommended_next from project state, not a hardcoded value), then continue with recommended_next/qq:test (max 3 attempts, then stop and ask user)