{"id":"b0f62154-44da-4210-a0a0-b1edc800bd03","shortId":"58QZNG","kind":"skill","title":"jahro-logging","tagline":"Reviews and improves Debug.Log usage in Unity C# projects following structured logging principles: context tags, severity contracts, boundary-based placement, and criticality tiers. Detects common antipatterns (naked Debug.Log, logging in Update, stringly-typed errors), adds miss","description":"# Unity Logging Best Practices\n\nHelp developers implement effective, structured logging in Unity C# projects. This skill is principle-driven and tool-agnostic — all guidance works with raw `Debug.Log`. Jahro is mentioned where it adds specific value, not as a requirement.\n\n## Passive Rules (Always Apply)\n\nWhen writing or editing Unity C# code, silently apply all of the following rules.\n\n### Structured format\n\nEvery log message follows this structure:\n\n```\n[Tag] Action — key=value, key=value\n```\n\nExamples:\n\n```\n[Save] File written — path=slot_01.sav, size=1.2MB, duration=340ms\n[Network] Connection timeout — host=192.168.1.1, attempts=3, elapsed=15.2s\n[Inventory] Item added — item=sword_01, slot=3, player=Player_7\n```\n\nNever write narrative-style logs like `\"The inventory system tried to add a sword but the slot was full.\"` — they are impossible to filter or parse at scale.\n\n### Severity contract\n\nUse the correct Unity call for each severity level:\n\n| Call | Level | Meaning | Examples |\n|:-----|:------|:--------|:---------|\n| `Debug.LogError` | Error | Unrecoverable failure | Null refs past fallback, failed network with no retry, corrupt save |\n| `Debug.LogWarning` | Warning | Unexpected but handled | Fallback used, deprecated API, performance budget exceeded |\n| `Debug.Log` | Info | Significant expected event | System initialized, scene loaded, purchase completed |\n| `Debug.Log` | Debug | Development-only detail | State transitions, cache hits/misses, intermediate values |\n\nUnity maps Info and Debug to the same `Debug.Log` call. Convey the distinction through message detail level, not the API call.\n\n### Context tags\n\nEvery log message starts with a `[Tag]` prefix identifying the producing system. Tags are:\n\n- **Short but descriptive**: `[Audio]`, `[Inventory]`, `[AI]` — not `[AudioManagerSystemController]`\n- **Consistent**: one name per system project-wide. Never `[Save]` in one file and `[SaveManager]` in another.\n- **Hierarchical when needed**: `[Network.Lobby]`, `[AI.Pathfinding]` for large systems.\n\nIf the project has a `LogTag` constants class, use its values. Otherwise, use the system/class name as the tag.\n\n### Criticality tiers\n\nAuto-classify the system being written/edited and adjust logging depth accordingly:\n\n**Tier 1 — Critical (maximum verbosity)**\nSystems: saves, IAP, auth, network, analytics.\nLog every state transition, decision branch, error with full context. Include timing, retry counts, correlation IDs.\n\n**Tier 2 — Gameplay (moderate verbosity)**\nSystems: player state, inventory, economy, quests, AI, scene management.\nLog state transitions, significant events, errors, warnings. Skip per-frame updates.\n\n**Tier 3 — Infrastructure (minimal verbosity)**\nSystems: physics, input, animation, audio, rendering, camera, UI navigation.\nLog initialization, errors, anomalies only. Never log per-frame operations.\n\nClassification heuristics by class/namespace name:\n\n| Pattern | Tier |\n|:--------|:-----|\n| `SaveManager`, `PurchaseController`, `AuthService`, `NetworkManager`, `AnalyticsDispatcher` | 1 |\n| `PlayerController`, `InventorySystem`, `QuestManager`, `AIController`, `EconomyManager` | 2 |\n| `CameraController`, `InputHandler`, `AudioManager`, `ParticleSpawner`, `AnimationDriver` | 3 |\n\n### Boundary logging\n\nLog at boundaries — the joints where things break. Skip internal computations.\n\n- **System boundaries**: when control passes between systems (log the handoff)\n- **State boundaries**: state machine transitions (log from/to/cause)\n- **Error boundaries**: `catch` blocks, null checks, validation failures (log diagnostics)\n- **External boundaries**: file I/O, HTTP, platform APIs (log request + response/error)\n\nDo NOT log: internal algorithm steps, per-frame position/velocity, routine success that happens 1000x/session, framework plumbing (`Awake` called, coroutine started).\n\n### Hot-path guards\n\nNever place unconditional `Debug.Log` in `Update()`, `FixedUpdate()`, `LateUpdate()`, or any per-frame method. These produce 60+ messages/second/instance, flood the console, and tank performance. If temporary frame-level logging is needed, guard it:\n\n```csharp\n[SerializeField] private bool debugMovement;\n\nvoid Update()\n{\n    if (debugMovement)\n        Debug.Log($\"[Player] Position — pos={transform.position}, vel={rb.velocity}\", this);\n}\n```\n\n### Context object\n\nIn MonoBehaviours, always pass `this` (or `gameObject`) as the second parameter to `Debug.Log`. This makes the log message clickable in the Unity Console — clicking it pings the source GameObject in the Hierarchy.\n\n```csharp\nDebug.Log($\"[Player] State changed — from={oldState}, to={newState}\", this);\nDebug.LogError($\"[Save] Write failed — path={filePath}, error={ex.Message}\", this);\n```\n\n### Sensitive data\n\nNever log credentials, tokens, passwords, emails, payment details, or PII. Mask or omit them:\n\n```csharp\nDebug.Log($\"[Auth] Login attempt — user={userId}, token=***\", this);\n```\n\n### Data formatting\n\n- **Numbers**: include units — `elapsed=340ms`, `size=1.2MB`, not bare numbers\n- **Vectors**: readable format — `pos=(12.3, 0.0, -4.5)`, not `pos=UnityEngine.Vector3`\n- **Enums**: log the name — `state=Jumping`, not `state=2`\n- **Collections**: count + sample — `items=[sword, shield] (2 total)` or `enemies=47 active`\n- **Null/missing**: be explicit — `target=<none>` or `target=null`, not omission\n- **Booleans**: descriptive — `grounded=true`, not `g=1`\n\n### Actionable errors\n\nError logs must say what happened, what was expected, and where to look:\n\n```csharp\n// BAD\nDebug.LogError(\"[Audio] AudioClip is null\");\n\n// GOOD\nDebug.LogError($\"[Audio] Clip not found — clip='{clipName}', expected at 'Audio/SFX/'. \" +\n    \"Check asset exists and is assigned in AudioConfig.\", this);\n```\n\n### Correlation IDs\n\nFor Tier 1 multi-step operations (purchases, scene loads, matchmaking), generate a shared ID that links all related logs:\n\n```csharp\nvar loadId = $\"load_{++_loadCounter}\";\nDebug.Log($\"[SceneLoader] Load started — scene={sceneName}, loadId={loadId}\", this);\n// ... later ...\nDebug.Log($\"[SceneLoader] Load completed — scene={sceneName}, duration={elapsed:F1}s, loadId={loadId}\", this);\n```\n\n---\n\n## Active Workflow: Review & Improve\n\nWhen the user asks to review, audit, or improve logging in existing code, follow this workflow.\n\n### 1. Ask logging setup\n\n> \"Do you use raw `Debug.Log` or a logging wrapper/helper class? I'll match my suggestions to your setup.\"\n\nAdapt all generated code to match the user's approach.\n\n### 2. Scan for antipatterns\n\nCheck the code against all 10 antipatterns (see Antipatterns section below). Report each finding with the specific line and a fix.\n\n### 3. Classify system tier\n\nDetermine Tier 1/2/3 from class name, namespace, and functionality. State the classification and explain why:\n\n> \"This is `SaveManager` — Tier 1 (critical system). I'll apply maximum logging verbosity: every state transition, every error path, correlation IDs for multi-step operations.\"\n\n### 4. Identify missing boundary logs\n\nCheck for:\n\n- **System boundaries**: calls to other managers/services without handoff logs\n- **State boundaries**: state machine transitions, enum changes without transition logs\n- **Error boundaries**: `try/catch` blocks, null checks without diagnostic logging\n- **External boundaries**: `File.`, `HttpClient.`, `PlayerPrefs.`, `UnityWebRequest`, platform API calls without request/response logs\n\n### 5. Generate improved code\n\nApply all passive rules to produce the improved version:\n\n- Structured format with `[Tag]`\n- Correct severity levels\n- Actionable error messages (what, expected, where to look)\n- Correlation IDs for Tier 1 multi-step operations\n- `this`/`gameObject` as context object in MonoBehaviours\n- Temporal context where relevant (`elapsed=340ms`, `frame={Time.frameCount}`)\n\n### 6. Verify\n\n> **Verify:** Enter Play Mode and trigger the code path you changed. Check the Unity Console — confirm log messages appear with the `[Tag] Action — key=value` format, correct severity icons (info/warning/error), and that clicking a message pings the source GameObject.\n\n---\n\n## Active Workflow: Setup Infrastructure\n\nWhen the user asks to set up logging conventions, standards, or infrastructure, follow this workflow.\n\n### 1. Ask about the project\n\n> \"What are your major systems? (e.g., save system, networking, inventory, AI, audio). How large is the team? Any existing logging conventions or wrapper classes?\"\n\n### 2. Generate LogTag constants class\n\nCustomize to the user's actual systems. Organize by criticality tier:\n\n```csharp\npublic static class LogTag\n{\n    // Tier 1 — Critical Systems\n    public const string Save     = \"Save\";\n    public const string Network  = \"Network\";\n    public const string IAP      = \"IAP\";\n    public const string Auth     = \"Auth\";\n\n    // Tier 2 — Gameplay Systems\n    public const string Player    = \"Player\";\n    public const string Inventory = \"Inventory\";\n    public const string Quest     = \"Quest\";\n    public const string AI        = \"AI\";\n\n    // Tier 3 — Infrastructure Systems\n    public const string Audio  = \"Audio\";\n    public const string Input  = \"Input\";\n    public const string Camera = \"Camera\";\n    public const string UI     = \"UI\";\n}\n```\n\n### 3. Generate optional logging helper\n\nOffer a lightweight static helper (< 80 lines) that enforces the structured format. The helper wraps `Debug.Log` — it is a formatting convenience, not a framework.\n\n```csharp\nusing UnityEngine;\nusing System.Text;\n\npublic static class Log\n{\n    public static void Info(string tag, string message, Object context = null)\n    {\n        Debug.Log(Format(tag, message), context);\n    }\n\n    public static void Warn(string tag, string message, Object context = null)\n    {\n        Debug.LogWarning(Format(tag, message), context);\n    }\n\n    public static void Error(string tag, string message, Object context = null)\n    {\n        Debug.LogError(Format(tag, message), context);\n    }\n\n    public static void Info(string tag, string action, params (string key, object value)[] data)\n    {\n        Debug.Log(Format(tag, action, data));\n    }\n\n    public static void Warn(string tag, string action, params (string key, object value)[] data)\n    {\n        Debug.LogWarning(Format(tag, action, data));\n    }\n\n    public static void Error(string tag, string action, params (string key, object value)[] data)\n    {\n        Debug.LogError(Format(tag, action, data));\n    }\n\n    [System.Diagnostics.Conditional(\"DEBUG\")]\n    public static void Debug(string tag, string message, Object context = null)\n    {\n        UnityEngine.Debug.Log(Format(tag, message), context);\n    }\n\n    private static string Format(string tag, string message) => $\"[{tag}] {message}\";\n\n    private static string Format(string tag, string action, (string key, object value)[] data)\n    {\n        var sb = new StringBuilder();\n        sb.Append('[').Append(tag).Append(\"] \").Append(action);\n        if (data.Length > 0)\n        {\n            sb.Append(\" \\u2014 \");\n            for (int i = 0; i < data.Length; i++)\n            {\n                if (i > 0) sb.Append(\", \");\n                sb.Append(data[i].key).Append('=').Append(data[i].value ?? \"<none>\");\n            }\n        }\n        return sb.ToString();\n    }\n}\n```\n\nKey design points to explain to the user:\n\n- `Log.Debug()` uses `[Conditional(\"DEBUG\")]` — calls are stripped from release builds by the compiler, zero overhead\n- All methods accept an optional `context` parameter for GameObject pinging\n- The params overload enforces `key=value` structure automatically\n- No reflection, no allocation beyond the formatted string\n- All principles work equally well with raw `Debug.Log` — this helper is optional\n\n### 4. Generate conventions reference\n\nProvide a brief inline summary the user can share with their team:\n\n- **Format**: `[Tag] Action — key=value, key=value`\n- **Severity**: Error = unrecoverable, Warning = handled unexpected, Info = significant expected, Debug = development detail\n- **Tiers**: Tier 1 (critical: saves, IAP, auth) = max verbosity, Tier 2 (gameplay) = moderate, Tier 3 (infrastructure) = minimal\n- **Where to log**: system boundaries, state transitions, error/catch blocks, external I/O\n- **Where NOT to log**: Update/FixedUpdate (without guards), internal computations, routine success, framework plumbing\n- **Data rules**: numbers with units, enum names not ints, explicit nulls, readable vectors\n- **Antipatterns**: naked Debug.Log, log-and-throw, stringly-typed errors, logging in Update, sensitive data in logs\n\n### 5. Verify\n\n> **Verify:** Add a test log to any system using the new LogTag constants and format. Enter Play Mode and check the Console — confirm the `[Tag] Action — key=value` format appears correctly.\n\n---\n\n## Log Format Reference\n\n### Message template\n\n```\n[Tag] Action — key=value, key=value\n```\n\nThe em dash (`—`) separates the human-readable action from machine-parseable key-value data. Both parts should be meaningful independently.\n\n### Severity mapping\n\n| Unity Call | Use For |\n|:-----------|:--------|\n| `Debug.LogError(msg, ctx)` | Failures that were NOT recovered: missing critical assets, data corruption, unhandled exceptions |\n| `Debug.LogWarning(msg, ctx)` | Unexpected situations that WERE handled: fallback values, deprecation, performance anomalies |\n| `Debug.Log(msg, ctx)` | Expected significant events (Info) + development detail (Debug) |\n\n### Game-specific logging domains\n\n| Domain | What to log | Example |\n|:-------|:------------|:--------|\n| Lifecycle | System init (with timing), dependency failures, config values | `[Game] Initialized — systems=12, duration=1.4s` |\n| State machines | Every transition (from/to/cause), invalid transitions | `[Player] State changed — from=Idle, to=Jumping, input=Space` |\n| Entity lifecycle | Spawn (with identity), destruction (with reason) | `[Spawner] Enemy spawned — type=Goblin, id=enemy_42, pos=(10, 0, 5)` |\n| Economy | Currency changes (delta + balance + source), purchases | `[Economy] Currency changed — type=Gold, delta=+150, source=QuestReward, balance=1280` |\n| Networking | Connection lifecycle, RPCs, sync conflicts, latency spikes | `[Network] Peer disconnected — peerId=42, reason=Timeout, duration=340s` |\n| Platform | Device info at session start (model, OS, memory, GPU) | `[Platform] Session started — device=iPhone14, os=iOS17.2, memory=6GB` |\n\n### Rich text (optional, Editor-only)\n\nUnity's Editor console supports rich text for visual differentiation. Use sparingly — colors must not carry meaning the plain text doesn't already convey, since device logs render tags as literal text.\n\n```csharp\nDebug.Log($\"<color=#6BCB77>[Save]</color> File written — path={filePath}\", this);\n```\n\n---\n\n## Antipatterns\n\nDetect and flag these when reviewing code. Each has a detection signal and a fix pattern.\n\n| # | Antipattern | Detection Signal | Fix |\n|:--|:------------|:-----------------|:----|\n| 1 | Naked Debug.Log | `Debug.Log(\"here\")`, `Debug.Log(variable)` — no tag, no context | Add `[Tag] Action — key=value` structure |\n| 2 | Log-and-throw | `catch` block that logs AND rethrows/throws | Log only at the handling boundary, not every catch in the chain |\n| 3 | Logging in Update | `Debug.Log` inside `Update()`/`FixedUpdate()`/`LateUpdate()` unconditionally | Remove, or guard with a `bool` toggle; suggest `[JahroWatch]` for value monitoring |\n| 4 | Stringly-typed errors | `Debug.LogError(\"Something went wrong\")` — no specifics | Add what happened, what was expected, where to look |\n| 5 | Inconsistent tags | Same system using `[Save]`, `[SaveManager]`, `[Persistence]` across files | Pick one tag, define it in `LogTag` constants |\n| 6 | Sensitive data | Passwords, tokens, emails, auth data in log calls | Mask with `***` or omit entirely |\n| 7 | ToString() logging | `Debug.Log(complexObject)` relying on default ToString | Extract specific fields into structured key=value format |\n| 8 | Commented-out logs | `// Debug.Log(...)` instead of proper severity/filtering | Delete if not useful, or convert to `Log.Debug()` / conditional |\n| 9 | Boolean-only errors | `if (!DoThing()) Debug.LogError(\"Failed\")` — no diagnostics | Return error details from the method, log what specifically failed |\n| 10 | Copy-pasted messages | Identical log text from different call sites | Add `[Tag]` and location-specific context to each |\n\n### Common fix examples\n\n**Naked Debug.Log → Structured:**\n\n```csharp\n// Before\nDebug.Log(\"item added\");\n\n// After\nDebug.Log($\"[Inventory] Item added — item={item.Id}, slot={slotIndex}, player={playerId}\", this);\n```\n\n**Logging in Update → JahroWatch or guarded:**\n\n```csharp\n// Before\nvoid Update() {\n    Debug.Log($\"Health: {health}\");\n}\n\n// After — use [JahroWatch] for continuous monitoring (if Jahro is available)\n[JahroWatch(\"Health\", \"Player\")]\npublic float health;\n\n// After — or guard with a toggle (works without Jahro)\n[SerializeField] private bool debugHealth;\nvoid Update() {\n    if (debugHealth) Debug.Log($\"[Player] Health tick — health={health}, frame={Time.frameCount}\", this);\n}\n```\n\n**Stringly-typed error → Actionable:**\n\n```csharp\n// Before\nDebug.LogError(\"Save failed\");\n\n// After\nDebug.LogError($\"[Save] Write failed — path={savePath}, error={ex.GetType().Name}: {ex.Message}. \" +\n    $\"Check write permissions and available disk space.\", this);\n```\n\n---\n\n## Jahro Integration (Optional)\n\nAll principles above work without Jahro. If the project uses Jahro, these features add specific value:\n\n| Principle | How Jahro Helps |\n|:----------|:----------------|\n| Context tag filtering | Jahro's log viewer filters by `[Tag]` prefix — structured tags become searchable categories, not just visual prefixes |\n| Dynamic verbosity | Create `[JahroCommand]` methods to toggle per-system log levels at runtime without recompiling |\n| Value monitoring | For values developers currently log per-frame, `[JahroWatch]` is a zero-log-noise alternative — values display in the Watcher tab only when open |\n| Log snapshots | Jahro Snapshots capture the full log stream and upload for team sharing — structured logs are far more valuable in shared snapshots |\n| LLM-ready logs | Structured format + Jahro snapshot export = ideal input for LLM debugging assistance |\n\n### Cross-references\n\n- To create runtime verbosity toggle commands → use the `jahro-commands` skill\n- To replace per-frame Debug.Log with live value monitoring → use the `jahro-watcher` skill\n- For production log stripping and build configuration → see the `jahro-production` skill\n- If Jahro is not installed but the user wants these features → use the `jahro-setup` skill\n- For Jahro-specific issues (console not opening, commands missing) → use the `jahro-troubleshooting` skill","tags":["jahro","logging","unity","agent","skills","jahro-console","agent-skills","ai-assistant","ai-coding","claude-code","cursor","debugging"],"capabilities":["skill","source-jahro-console","skill-jahro-logging","topic-agent-skills","topic-ai-assistant","topic-ai-coding","topic-claude-code","topic-cursor","topic-debugging","topic-gamedev","topic-in-game-console","topic-jahro","topic-logging","topic-unity","topic-unity-package"],"categories":["unity-agent-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/jahro-console/unity-agent-skills/jahro-logging","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add jahro-console/unity-agent-skills","source_repo":"https://github.com/jahro-console/unity-agent-skills","install_from":"skills.sh"}},"qualityScore":"0.456","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 12 github stars · SKILL.md body (18,692 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:07:09.016Z","embedding":null,"createdAt":"2026-04-23T13:04:13.653Z","updatedAt":"2026-05-18T19:07:09.016Z","lastSeenAt":"2026-05-18T19:07:09.016Z","tsv":"'+150':1782 '-4.5':671 '0':1403,1409,1415,1767 '0.0':670 '01':142 '1':346,435,711,758,824,904,1005,1085,1136,1526,1892 '1.2':123,660 '1.4':1731 '1/2/3':887 '10':865,1766,2066 '1000x/session':512 '12':1729 '12.3':669 '1280':1786 '15.2':135 '192.168.1.1':131 '2':373,441,683,690,856,1114,1160,1534,1909 '3':133,144,399,447,881,1184,1207,1538,1932 '340ms':126,658,1022 '340s':1803 '4':926,1489,1954 '42':1764,1799 '47':694 '5':973,1596,1768,1974 '6':1025,1993 '60':539 '6bcb77':1864 '6gb':1822 '7':147,2009 '8':2026 '80':1217 '9':2045 'accept':1453 'accord':344 'across':1983 'action':111,712,993,1049,1300,1310,1319,1329,1338,1348,1385,1400,1507,1623,1635,1648,1905,2169 'activ':695,804,1066 'actual':1124 'ad':139,2097,2102 'adapt':846 'add':40,77,160,1599,1903,1965,2078,2210 'adjust':341 'agnost':65 'ai':284,383,1100,1181,1182 'ai.pathfinding':308 'aicontrol':439 'algorithm':502 'alloc':1472 'alreadi':1851 'altern':2270 'alway':86,578 'analyt':355 'analyticsdispatch':434 'anim':406 'animationdriv':446 'anomali':415,1696 'anoth':303 'antipattern':30,859,866,868,1578,1871,1888 'api':215,261,494,968 'appear':1045,1627 'append':1396,1398,1399,1421,1422 'appli':87,96,909,977 'approach':855 'ask':811,825,1073,1086 'asset':746,1679 'assign':750 'assist':2317 'attempt':132,647 'audio':282,407,730,736,1101,1190,1191 'audio/sfx':744 'audioclip':731 'audioconfig':752 'audiomanag':444 'audiomanagersystemcontrol':286 'audit':814 'auth':353,645,1157,1158,1530,1999 'authservic':432 'auto':334 'auto-classifi':333 'automat':1468 'avail':2132,2190 'awak':515 'bad':728 'balanc':1773,1785 'bare':663 'base':23 'becom':2230 'best':44 'beyond':1473 'block':481,955,1549,1915 'bool':560,1947,2150 'boolean':705,2047 'boolean-on':2046 'boundari':22,448,452,462,472,479,489,929,934,943,953,962,1545,1925 'boundary-bas':21 'branch':361 'break':457 'brief':1495 'budget':217 'build':1445,2354 'c':11,54,93 'cach':238 'call':183,188,251,262,516,935,969,1440,1666,2003,2076 'camera':409,1200,1201 'cameracontrol':442 'captur':2284 'carri':1844 'catch':480,1914,1928 'categori':2232 'chain':1931 'chang':612,948,1037,1742,1771,1778 'check':483,745,860,931,957,1038,1617,2186 'class':319,837,889,1113,1118,1133,1243 'class/namespace':426 'classif':423,896 'classifi':335,882 'click':599,1059 'clickabl':594 'clip':737,740 'clipnam':741 'code':94,820,849,862,976,1034,1878 'collect':684 'color':1841,1863 'command':2326,2331,2387 'comment':2028 'commented-out':2027 'common':29,2087 'compil':1448 'complet':229,794 'complexobject':2013 'comput':460,1560 'condit':1438,2044 'config':1724 'configur':2355 'confirm':1042,1620 'conflict':1792 'connect':128,1788 'consist':287 'consol':543,598,1041,1619,1832,2384 'const':1140,1145,1150,1155,1164,1169,1174,1179,1188,1193,1198,1203 'constant':318,1117,1610,1992 'context':17,263,365,574,1013,1018,1254,1260,1270,1276,1286,1292,1361,1367,1456,1902,2084,2217 'continu':2127 'contract':20,178 'control':464 'conveni':1232 'convent':1078,1110,1491 'convert':2041 'convey':252,1852 'copi':2068 'copy-past':2067 'coroutin':517 'correct':181,990,1053,1628 'correl':370,754,919,1001 'corrupt':205,1681 'count':369,685 'creat':2239,2322 'credenti':631 'critic':26,331,347,905,1128,1137,1527,1678 'cross':2319 'cross-refer':2318 'csharp':557,608,643,727,776,1130,1236,1861,2093,2116,2170 'ctx':1671,1686,1699 'currenc':1770,1777 'current':2258 'custom':1119 'dash':1642 'data':628,652,1306,1311,1325,1330,1344,1349,1390,1418,1423,1565,1593,1656,1680,1995,2000 'data.length':1402,1411 'debug':231,246,1351,1355,1439,1521,1706,2316 'debug.log':7,32,71,219,230,250,526,566,588,609,644,781,791,832,1227,1256,1307,1484,1580,1697,1862,1894,1895,1897,1936,2012,2031,2091,2095,2099,2120,2156,2338 'debug.logerror':192,618,729,735,1288,1345,1669,1959,2052,2172,2176 'debug.logwarning':207,1272,1326,1684 'debughealth':2151,2155 'debugmov':561,565 'decis':360 'default':2016 'defin':1988 'delet':2036 'delta':1772,1781 'depend':1722 'deprec':214,1694 'depth':343 'descript':281,706 'design':1429 'destruct':1754 'detail':235,257,636,1523,1705,2058 'detect':28,1872,1882,1889 'determin':885 'develop':47,233,1522,1704,2257 'development-on':232 'devic':1805,1817,1854 'diagnost':487,959,2055 'differ':2075 'differenti':1838 'disconnect':1797 'disk':2191 'display':2272 'distinct':254 'doesn':1849 'domain':1711,1712 'doth':2051 'driven':61 'durat':125,797,1730,1802 'dynam':2237 'e.g':1095 'economi':381,1769,1776 'economymanag':440 'edit':91 'editor':1827,1831 'editor-on':1826 'effect':49 'elaps':134,657,798,1021 'em':1641 'email':634,1998 'enemi':693,1758,1763 'enforc':1220,1464 'enter':1028,1613 'entir':2008 'entiti':1749 'enum':675,947,1570 'equal':1480 'error':39,193,362,391,414,478,624,713,714,917,952,994,1280,1334,1513,1588,1958,2049,2057,2168,2182 'error/catch':1548 'event':223,390,1702 'everi':104,265,357,913,916,1735,1927 'ex.gettype':2183 'ex.message':625,2185 'exampl':116,191,1716,2089 'exceed':218 'except':1683 'exist':747,819,1108 'expect':222,722,742,997,1520,1700,1970 'explain':898,1432 'explicit':698,1574 'export':2311 'extern':488,961,1550 'extract':2018 'f1':799 'fail':200,621,2053,2065,2174,2179 'failur':195,485,1672,1723 'fallback':199,212,1692 'far':2297 'featur':2209,2372 'field':2020 'file':118,299,490,963,1866,1984 'filepath':623,1869 'filter':172,2219,2224 'find':873 'fix':880,1886,1891,2088 'fixedupd':529,1939 'flag':1874 'float':2137 'flood':541 'follow':13,100,107,821,1082 'format':103,653,667,987,1052,1223,1231,1257,1273,1289,1308,1327,1346,1364,1371,1381,1475,1505,1612,1626,1630,2025,2308 'found':739 'frame':396,421,506,535,550,1023,2162,2262,2337 'frame-level':549 'framework':513,1235,1563 'from/to/cause':477,1737 'full':167,364,2286 'function':893 'g':710 'game':1708,1726 'game-specif':1707 'gameobject':582,604,1011,1065,1459 'gameplay':374,1161,1535 'generat':767,848,974,1115,1208,1490 'goblin':1761 'gold':1780 'good':734 'gpu':1813 'ground':707 'guard':522,555,1558,1944,2115,2141 'guidanc':67 'handl':211,1516,1691,1924 'handoff':470,940 'happen':511,719,1967 'health':2121,2122,2134,2138,2158,2160,2161 'help':46,2216 'helper':1211,1216,1225,1486 'heurist':424 'hierarch':304 'hierarchi':607 'hits/misses':239 'host':130 'hot':520 'hot-path':519 'http':492 'httpclient':964 'human':1646 'human-read':1645 'i/o':491,1551 'iap':352,1152,1153,1529 'icon':1055 'id':371,755,770,920,1002,1762 'ideal':2312 'ident':1753,2071 'identifi':273,927 'idl':1744 'implement':48 'imposs':170 'improv':6,807,816,975,984 'includ':366,655 'inconsist':1975 'independ':1662 'info':220,244,1248,1296,1518,1703,1806 'info/warning/error':1056 'infrastructur':400,1069,1081,1185,1539 'init':1719 'initi':225,413,1727 'inlin':1496 'input':405,1195,1196,1747,2313 'inputhandl':443 'insid':1937 'instal':2366 'instead':2032 'int':1407,1573 'integr':2195 'intermedi':240 'intern':459,501,1559 'invalid':1738 'inventori':137,156,283,380,1099,1171,1172,2100 'inventorysystem':437 'ios17.2':1820 'iphone14':1818 'issu':2383 'item':138,140,687,2096,2101,2103 'item.id':2104 'jahro':2,72,2130,2147,2194,2202,2207,2215,2220,2282,2309,2330,2346,2359,2363,2376,2381,2392 'jahro-command':2329 'jahro-log':1 'jahro-product':2358 'jahro-setup':2375 'jahro-specif':2380 'jahro-troubleshoot':2391 'jahro-watch':2345 'jahrocommand':2240 'jahrowatch':1950,2113,2125,2133,2263 'joint':454 'jump':680,1746 'key':112,114,1050,1303,1322,1341,1387,1420,1428,1465,1508,1510,1624,1636,1638,1654,1906,2023 'key-valu':1653 'larg':310,1103 'latenc':1793 'later':790 'lateupd':530,1940 'level':187,189,258,551,992,2248 'lifecycl':1717,1750,1789 'lightweight':1214 'like':154 'line':877,1218 'link':772 'liter':1859 'live':2340 'll':839,908 'llm':2304,2315 'llm-readi':2303 'load':227,765,779,783,793 'loadcount':780 'loadid':778,787,788,801,802 'locat':2082 'location-specif':2081 'log':3,15,33,43,51,105,153,266,342,356,386,412,418,449,450,468,476,486,495,500,552,592,630,676,715,775,817,826,835,911,930,941,951,960,972,1043,1077,1109,1210,1244,1543,1555,1582,1589,1595,1602,1629,1710,1715,1855,1911,1917,1920,1933,2002,2011,2030,2062,2072,2110,2222,2247,2259,2268,2280,2287,2295,2306,2351 'log-and-throw':1581,1910 'log.debug':1436,2043 'login':646 'logtag':317,1116,1134,1609,1991 'look':726,1000,1973 'machin':474,945,1651,1734 'machine-pars':1650 'major':1093 'make':590 'manag':385 'managers/services':938 'map':243,1664 'mask':639,2004 'match':840,851 'matchmak':766 'max':1531 'maximum':348,910 'mb':124,661 'mean':190,1845 'meaning':1661 'memori':1812,1821 'mention':74 'messag':106,256,267,593,995,1044,1061,1252,1259,1268,1275,1284,1291,1359,1366,1375,1377,1632,2070 'messages/second/instance':540 'method':536,1452,2061,2241 'minim':401,1540 'miss':41,928,1677,2388 'mode':1030,1615 'model':1810 'moder':375,1536 'monitor':1953,2128,2254,2342 'monobehaviour':577,1016 'msg':1670,1685,1698 'multi':760,923,1007 'multi-step':759,922,1006 'must':716,1842 'nake':31,1579,1893,2090 'name':289,327,427,678,890,1571,2184 'namespac':891 'narrat':151 'narrative-styl':150 'navig':411 'need':306,554 'network':127,201,354,1098,1147,1148,1787,1795 'network.lobby':307 'networkmanag':433 'never':148,295,417,523,629 'new':1393,1608 'newstat':616 'nois':2269 'null':196,482,702,733,956,1255,1271,1287,1362,1575 'null/missing':696 'number':654,664,1567 'object':575,1014,1253,1269,1285,1304,1323,1342,1360,1388 'offer':1212 'oldstat':614 'omiss':704 'omit':641,2007 'one':288,298,1986 'open':2279,2386 'oper':422,762,925,1009 'option':1209,1455,1488,1825,2196 'organ':1126 'os':1811,1819 'otherwis':323 'overhead':1450 'overload':1463 'param':1301,1320,1339,1462 'paramet':586,1457 'pars':174 'parseabl':1652 'part':1658 'particlespawn':445 'pass':465,579 'passiv':84,979 'password':633,1996 'past':198,2069 'path':120,521,622,918,1035,1868,2180 'pattern':428,1887 'payment':635 'peer':1796 'peerid':1798 'per':290,395,420,505,534,2245,2261,2336 'per-fram':394,419,504,533,2260,2335 'per-system':2244 'perform':216,546,1695 'permiss':2188 'persist':1982 'physic':404 'pick':1985 'pii':638 'ping':601,1062,1460 'place':524 'placement':24 'plain':1847 'platform':493,967,1804,1814 'play':1029,1614 'player':145,146,378,567,610,1166,1167,1740,2107,2135,2157 'playercontrol':436 'playerid':2108 'playerpref':965 'plumb':514,1564 'point':1430 'pos':569,668,673,1765 'posit':568 'position/velocity':507 'practic':45 'prefix':272,2227,2236 'principl':16,60,1478,2198,2213 'principle-driven':59 'privat':559,1368,1378,2149 'produc':275,538,982 'product':2350,2360 'project':12,55,293,314,1089,2205 'project-wid':292 'proper':2034 'provid':1493 'public':1131,1139,1144,1149,1154,1163,1168,1173,1178,1187,1192,1197,1202,1241,1245,1261,1277,1293,1312,1331,1352,2136 'purchas':228,763,1775 'purchasecontrol':431 'quest':382,1176,1177 'questmanag':438 'questreward':1784 'raw':70,831,1483 'rb.velocity':572 'readabl':666,1576,1647 'readi':2305 'reason':1756,1800 'recompil':2252 'recov':1676 'ref':197 'refer':1492,1631,2320 'reflect':1470 'relat':774 'releas':1444 'relev':1020 'reli':2014 'remov':1942 'render':408,1856 'replac':2334 'report':871 'request':496 'request/response':971 'requir':83 'response/error':497 'rethrows/throws':1919 'retri':204,368 'return':1426,2056 'review':4,806,813,1877 'rich':1823,1834 'routin':508,1561 'rpcs':1790 'rule':85,101,980,1566 'runtim':2250,2323 'sampl':686 'save':117,206,296,351,619,1096,1142,1143,1528,1865,1980,2173,2177 'savemanag':301,430,902,1981 'savepath':2181 'say':717 'sb':1392 'sb.append':1395,1404,1416,1417 'sb.tostring':1427 'scale':176 'scan':857 'scene':226,384,764,785,795 'sceneload':782,792 'scenenam':786,796 'searchabl':2231 'second':585 'section':869 'see':867,2356 'sensit':627,1592,1994 'separ':1643 'serializefield':558,2148 'session':1808,1815 'set':1075 'setup':827,845,1068,2377 'sever':19,177,186,991,1054,1512,1663 'severity/filtering':2035 'share':769,1501,2293,2301 'shield':689 'short':279 'signal':1883,1890 'signific':221,389,1519,1701 'silent':95 'sinc':1853 'site':2077 'situat':1688 'size':122,659 'skill':57,2332,2348,2361,2378,2394 'skill-jahro-logging' 'skip':393,458 'slot':143,165,2105 'slot_01.sav':121 'slotindex':2106 'snapshot':2281,2283,2302,2310 'someth':1960 'sourc':603,1064,1774,1783 'source-jahro-console' 'space':1748,2192 'spare':1840 'spawn':1751,1759 'spawner':1757 'specif':78,876,1709,1964,2019,2064,2083,2211,2382 'spike':1794 'standard':1079 'start':268,518,784,1809,1816 'state':236,358,379,387,471,473,611,679,682,894,914,942,944,1546,1733,1741 'static':1132,1215,1242,1246,1262,1278,1294,1313,1332,1353,1369,1379 'step':503,761,924,1008 'stream':2288 'string':37,1141,1146,1151,1156,1165,1170,1175,1180,1189,1194,1199,1204,1249,1251,1265,1267,1281,1283,1297,1299,1302,1316,1318,1321,1335,1337,1340,1356,1358,1370,1372,1374,1380,1382,1384,1386,1476,1586,1956,2166 'stringbuild':1394 'stringly-typ':36,1585,1955,2165 'strip':1442,2352 'structur':14,50,102,109,986,1222,1467,1908,2022,2092,2228,2294,2307 'style':152 'success':509,1562 'suggest':842,1949 'summari':1497 'support':1833 'sword':141,162,688 'sync':1791 'system':157,224,276,291,311,337,350,377,403,461,467,883,906,933,1094,1097,1125,1138,1162,1186,1544,1605,1718,1728,1978,2246 'system.diagnostics.conditional':1350 'system.text':1240 'system/class':326 'tab':2276 'tag':18,110,264,271,277,330,989,1048,1250,1258,1266,1274,1282,1290,1298,1309,1317,1328,1336,1347,1357,1365,1373,1376,1383,1397,1506,1622,1634,1857,1900,1904,1976,1987,2079,2218,2226,2229 'tank':545 'target':699,701 'team':1106,1504,2292 'templat':1633 'tempor':1017 'temporari':548 'test':1601 'text':1824,1835,1848,1860,2073 'thing':456 'throw':1584,1913 'tick':2159 'tier':27,332,345,372,398,429,757,884,886,903,1004,1129,1135,1159,1183,1524,1525,1533,1537 'time':367,1721 'time.framecount':1024,2163 'timeout':129,1801 'toggl':1948,2144,2243,2325 'token':632,650,1997 'tool':64 'tool-agnost':63 'topic-agent-skills' 'topic-ai-assistant' 'topic-ai-coding' 'topic-claude-code' 'topic-cursor' 'topic-debugging' 'topic-gamedev' 'topic-in-game-console' 'topic-jahro' 'topic-logging' 'topic-unity' 'topic-unity-package' 'tostr':2010,2017 'total':691 'transform.position':570 'transit':237,359,388,475,915,946,950,1547,1736,1739 'tri':158 'trigger':1032 'troubleshoot':2393 'true':708 'try/catch':954 'type':38,1587,1760,1779,1957,2167 'u2014':1405 'ui':410,1205,1206 'uncondit':525,1941 'unexpect':209,1517,1687 'unhandl':1682 'unit':656,1569 'uniti':10,42,53,92,182,242,597,1040,1665,1829 'unityengin':1238 'unityengine.debug.log':1363 'unityengine.vector3':674 'unitywebrequest':966 'unrecover':194,1514 'updat':35,397,528,563,1591,1935,1938,2112,2119,2153 'update/fixedupdate':1556 'upload':2290 'usag':8 'use':179,213,320,324,830,1237,1239,1437,1606,1667,1839,1979,2039,2124,2206,2327,2343,2373,2389 'user':648,810,853,1072,1122,1435,1499,2369 'userid':649 'valid':484 'valu':79,113,115,241,322,1051,1305,1324,1343,1389,1425,1466,1509,1511,1625,1637,1639,1655,1693,1725,1907,1952,2024,2212,2253,2256,2271,2341 'valuabl':2299 'var':777,1391 'variabl':1898 'vector':665,1577 'vel':571 'verbos':349,376,402,912,1532,2238,2324 'verifi':1026,1027,1597,1598 'version':985 'viewer':2223 'visual':1837,2235 'void':562,1247,1263,1279,1295,1314,1333,1354,2118,2152 'want':2370 'warn':208,392,1264,1315,1515 'watcher':2275,2347 'well':1481 'went':1961 'wide':294 'without':939,949,958,970,1557,2146,2201,2251 'work':68,1479,2145,2200 'workflow':805,823,1067,1084 'wrap':1226 'wrapper':1112 'wrapper/helper':836 'write':89,149,620,2178,2187 'written':119,1867 'written/edited':339 'wrong':1962 'zero':1449,2267 'zero-log-nois':2266","prices":[{"id":"d2ab1ea9-e445-4074-a7ae-d318c2854ffd","listingId":"b0f62154-44da-4210-a0a0-b1edc800bd03","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"jahro-console","category":"unity-agent-skills","install_from":"skills.sh"},"createdAt":"2026-04-23T13:04:13.653Z"}],"sources":[{"listingId":"b0f62154-44da-4210-a0a0-b1edc800bd03","source":"github","sourceId":"jahro-console/unity-agent-skills/jahro-logging","sourceUrl":"https://github.com/jahro-console/unity-agent-skills/tree/main/skills/jahro-logging","isPrimary":false,"firstSeenAt":"2026-04-23T13:04:13.653Z","lastSeenAt":"2026-05-18T19:07:09.016Z"}],"details":{"listingId":"b0f62154-44da-4210-a0a0-b1edc800bd03","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"jahro-console","slug":"jahro-logging","github":{"repo":"jahro-console/unity-agent-skills","stars":12,"topics":["agent-skills","ai-assistant","ai-coding","claude-code","cursor","debugging","gamedev","in-game-console","jahro","logging","unity","unity-package","unity3d"],"license":"mit","html_url":"https://github.com/jahro-console/unity-agent-skills","pushed_at":"2026-03-20T15:39:45Z","description":"Agent skills for AI-assisted Unity debugging — structured logging, runtime commands, variable watching, and more","skill_md_sha":"f0cf7602372fa2c04b43c509d3ebe06025aa201a","skill_md_path":"skills/jahro-logging/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/jahro-console/unity-agent-skills/tree/main/skills/jahro-logging"},"layout":"multi","source":"github","category":"unity-agent-skills","frontmatter":{"name":"jahro-logging","description":"Reviews and improves Debug.Log usage in Unity C# projects following structured logging principles: context tags, severity contracts, boundary-based placement, and criticality tiers. Detects common antipatterns (naked Debug.Log, logging in Update, stringly-typed errors), adds missing logs at system/state/error/external boundaries, and scaffolds project-wide logging infrastructure (LogTag constants, formatting helpers, conventions). Use when the user mentions logging, Debug.Log, log messages, debugging, or asks to improve observability in Unity code."},"skills_sh_url":"https://skills.sh/jahro-console/unity-agent-skills/jahro-logging"},"updatedAt":"2026-05-18T19:07:09.016Z"}}