Unity-agent-skills jahro-commands
git clone https://github.com/jahro-console/unity-agent-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/jahro-console/unity-agent-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/jahro-commands" ~/.claude/skills/jahro-console-unity-agent-skills-jahro-commands && rm -rf "$T"
skills/jahro-commands/SKILL.mdJahro Commands
Help users add runtime-callable debug commands to Unity code using Jahro's
[JahroCommand] attribute system.
Workflow
- Analyze the user's code — identify methods that are good command candidates
- Generate correct
attributes with proper syntax[JahroCommand] - Add registration if needed (instance methods require
)RegisterObject - VERIFY — "Enter Play Mode, press ~, check the Commands tab"
Analyzing Code for Command Candidates
When the user shares a class, identify methods worth exposing as commands:
Good candidates:
- Public methods that change game state (damage, heal, spawn, teleport, reset)
- Methods used for testing and tuning (set difficulty, add currency, skip level)
- Diagnostic methods (print stats, dump state, force GC)
- Methods with simple parameter types (int, float, bool, string, Vector2, Vector3, enum)
Skip these:
- Unity lifecycle methods (Update, Start, Awake, OnEnable, OnDisable, OnDestroy)
- Private implementation details the developer wouldn't want to call manually
- Methods with complex parameter types (custom classes, interfaces, delegates)
- Property getters/setters (use
for monitoring instead)[JahroWatch]
Attribute Syntax
[JahroCommand("command-name", "GroupName", "Short description of what it does")]
Constructor:
[JahroCommand(string name, string group, string description)]
All parameters are optional. Defaults: name = method name, group = "Default", description = "".
Naming conventions
- Command name: kebab-case (
,"spawn-enemy"
,"add-gold"
)"set-difficulty" - Group name: PascalCase or Title Case (
,"Cheats"
,"Spawning"
)"Game" - Description: Imperative, concise (
,"Spawn enemy at position"
)"Add gold to player"
Complete example
using JahroConsole; using UnityEngine; public class PlayerController : MonoBehaviour { public float health = 100f; [JahroCommand("heal", "Player", "Restore health by amount")] public void Heal(float amount) { health = Mathf.Min(health + amount, 100f); } [JahroCommand("teleport", "Player", "Teleport to position")] public void Teleport(Vector3 position) { transform.position = position; } [JahroCommand("reset-pos", "Player", "Reset to origin")] public void ResetPosition() { transform.position = Vector3.zero; } void OnEnable() => Jahro.RegisterObject(this); void OnDisable() => Jahro.UnregisterObject(this); }
Registration Pattern
Instance methods — require RegisterObject
Any non-static method with
[JahroCommand] needs the owning object registered so Jahro can invoke it:
void OnEnable() => Jahro.RegisterObject(this); void OnDisable() => Jahro.UnregisterObject(this);
This same call also registers
[JahroWatch] attributes on the class. If the class already has RegisterObject (e.g., for watchers), do not add a second call.
Read
references/common-patterns.md for the full lifecycle pattern and anti-patterns.
Static methods — no registration needed
Static methods are discovered via assembly scanning:
public class DebugCommands { [JahroCommand("restart-level", "Game", "Restart current level")] public static void RestartLevel() { UnityEngine.SceneManagement.SceneManager.LoadScene(0); } }
Decision guide
| Method type | Needs RegisterObject? | Why |
|---|---|---|
(instance) | Yes | Jahro needs the object reference to call it |
| No | Called on the class, discovered via assembly scan |
on a class that already has RegisterObject | No extra work | Already registered |
Supported Parameter Types
Commands accept these parameter types:
| Type | Text Mode input | Visual Mode input |
|---|---|---|
| | Number field |
| | Decimal field |
| / | Toggle switch |
| | Text field |
| | X/Y fields |
| | X/Y/Z fields |
(any) | (name) | Dropdown selector |
Maximum 3 parameters per command. For full type details, read
references/api-reference.md.
Command Overloads
Same command name with different parameter signatures:
[JahroCommand("spawn-enemy", "Spawning", "Spawn one enemy at position")] public void SpawnEnemy(Vector3 position) { /* ... */ } [JahroCommand("spawn-enemy", "Spawning", "Spawn N enemies")] public void SpawnEnemy(int count) { /* ... */ }
Text Mode resolves the correct overload by parameter count and type conversion.
Return Values
Commands that return
string display the result in the console log:
[JahroCommand("get-pos", "Debug", "Print player position")] public static string GetPlayerPosition() { return $"Position: {Player.Instance.transform.position}"; }
Dynamic Command Registration
For commands created at runtime instead of compile time. Use when wrapping external APIs, creating commands from data, or in non-MonoBehaviour systems.
// No parameters Jahro.RegisterCommand("clear-cache", "Maintenance", "Clear local cache", () => PlayerPrefs.DeleteAll()); // One typed parameter Jahro.RegisterCommand<int>("add-gold", "Cheats", "Add gold", amount => Player.Gold += amount); // Two parameters Jahro.RegisterCommand<int, float>("set-stats", "Tuning", "Set health and speed", (health, speed) => { Player.Health = health; Player.Speed = speed; });
Parameter order for dynamic registration:
(name, description, groupName, callback).
This differs from the attribute order (name, group, description).
Register command on existing object method:
var mgr = FindObjectOfType<GameManager>(); Jahro.RegisterCommand("restart", "Game", "Restart level", mgr, nameof(GameManager.RestartLevel));
Cleanup:
Jahro.UnregisterCommand("clear-cache"); Jahro.UnregisterCommand("restart", "Game");
Read
references/api-reference.md for all RegisterCommand overloads (0-3 generic parameters).
Command Organization
Group naming strategy
Organize commands by functional area:
"Player" — heal, teleport, reset, set-speed "Spawning" — spawn-enemy, spawn-wave, clear-enemies "Cheats" — god-mode, add-gold, unlock-all "Game" — restart-level, set-difficulty, skip-level "Debug" — dump-state, gc-collect, toggle-fps
Visual Mode vs Text Mode
Commands work in both modes automatically. Consider the target audience:
- Text Mode — fast for developers who know command names. Autocomplete helps. Vector3 entered as
.10 2.5 -7 - Visual Mode — browsable groups with descriptions, form-based parameter input. Touch-friendly on mobile. Enum parameters render as dropdown selectors.
When designing commands for QA (non-developers), prefer:
- Simple parameter types (bool, enum, int) over Vector3
- Descriptive names and descriptions
- Logical groups that match QA workflows
Favorites and Recent
Users can star frequently-used commands for quick access. The last 10 executed commands always appear in the Recent section. Command names and groups help discoverability — be descriptive.
Contextual Awareness
When you see these patterns in user code, proactively suggest:
| Pattern in code | Suggestion |
|---|---|
already present | Offer improvements (better groups, descriptions, missing commands) |
with debug commands | Migrate to — Visual Mode replaces the button UI |
| Public methods that modify game state | Suggest exposing as commands |
| Custom command parser (string → command) | Migrate to Jahro's typed command system |
Verification
After generating commands, always include:
Verify: Enter Play Mode → press ~ → switch to the Commands tab (or Visual Mode). Confirm your commands appear in the correct groups. Try executing one to confirm it works.
If commands don't appear, suggest the jahro-troubleshooting skill — common causes: missing RegisterObject, wrong assembly selected, JAHRO_DISABLE active.